1use alloc::vec::Vec;
10use core::fmt;
11
12use crate::error::{ByteOffset, DecodeContext, DecodeError, DecodeErrorKind};
13use crate::types::{
14 BlockType, DataIdx, ElemIdx, FuncIdx, GlobalIdx, LabelIdx, LocalIdx, MemIdx, RefType, TableIdx,
15 TypeIdx, ValType,
16};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct ValidationError {
21 pub offset: ByteOffset,
22 pub function: Option<FuncIdx>,
23 pub kind: ValidationErrorKind,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum ValidationErrorKind {
29 UnknownTypeIdx {
30 idx: TypeIdx,
31 },
32 UnknownFuncIdx {
33 idx: FuncIdx,
34 },
35 UndeclaredFuncRef {
36 idx: FuncIdx,
37 },
38 UnknownLocalIdx {
39 idx: LocalIdx,
40 },
41 UninitializedLocal {
42 idx: LocalIdx,
43 },
44 UnknownGlobalIdx {
45 idx: GlobalIdx,
46 available: u32,
47 },
48 UnknownTableIdx {
49 idx: TableIdx,
50 available: u32,
51 },
52 UnknownMemIdx {
53 idx: MemIdx,
54 available: u32,
55 },
56 UnknownDataIdx {
57 idx: DataIdx,
58 available: u32,
59 },
60 UnknownElemIdx {
61 idx: ElemIdx,
62 available: u32,
63 },
64 InvalidMemArgAlign {
65 op: &'static str,
66 max: u32,
67 found: u32,
68 },
69 InvalidSimdLaneIdx {
70 op: &'static str,
71 max: u8,
72 found: u8,
73 },
74 UnknownLabelIdx {
75 idx: LabelIdx,
76 },
77 Decode {
78 context: DecodeContext,
79 kind: DecodeErrorKind,
80 },
81 InvalidGlobalInitExpr,
82 NonConstantGlobalInitExpr,
83 MutableGlobalInInitExpr {
84 idx: GlobalIdx,
85 },
86 ImmutableGlobalSet {
87 idx: GlobalIdx,
88 },
89 GlobalInitTypeMismatch {
90 expected: ValType,
91 found: ValType,
92 },
93 BranchTypeMismatch {
94 label: LabelIdx,
95 expected: Vec<ValType>,
96 found: Vec<ValType>,
97 },
98 InvalidBrOnNonNullTarget {
99 label: LabelIdx,
100 found: Vec<ValType>,
101 },
102 InconsistentBranchTypes {
103 expected: Vec<ValType>,
104 found: Vec<ValType>,
105 },
106 UnexpectedElse,
107 UnexpectedEnd,
108 UnterminatedControlFrames,
109 ElseOutsideIf,
110 MissingElseForResult,
111 InvalidBlockType {
112 block_type: BlockType,
113 },
114 ControlResultTypeMismatch {
115 expected: Vec<ValType>,
116 found: Vec<ValType>,
117 },
118 InvalidSelectResultArity {
119 found: usize,
120 },
121 SelectOperandTypeMismatch {
122 expected: ValType,
123 found: Vec<ValType>,
124 },
125 StackUnderflow {
126 op: &'static str,
127 expected: Vec<ValType>,
128 available: Vec<ValType>,
129 },
130 TypeMismatch {
131 op: &'static str,
132 expected: ValType,
133 found: ValType,
134 },
135 FunctionResultTypeMismatch {
136 expected: Vec<ValType>,
137 found: Vec<ValType>,
138 full_stack: Vec<ValType>,
139 },
140 ResultTypeMismatch {
141 expected: Vec<ValType>,
142 found: Vec<ValType>,
143 },
144 InvalidStartFunctionType {
145 params: Vec<ValType>,
146 results: Vec<ValType>,
147 },
148 InvalidElementExpr,
149 NonConstantElementExpr,
150 ElementExprTypeMismatch {
151 expected: ValType,
152 found: ValType,
153 },
154 ElementTableTypeMismatch {
155 expected: RefType,
156 found: RefType,
157 },
158 InvalidCallIndirectTableType {
159 expected: RefType,
160 found: RefType,
161 },
162 MissingDataCountSection {
163 op: &'static str,
164 },
165 MemorySizeOutOfRange,
166 MemoryMinExceedsMax,
167 TableTypeMismatch,
169 DuplicateExportName {
170 name: alloc::string::String,
171 },
172}
173
174impl fmt::Display for ValidationError {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 match self.function {
177 Some(func) => write!(
178 f,
179 "validation error at byte {} in function {}: {}",
180 self.offset.0, func.0, self.kind
181 ),
182 None => write!(
183 f,
184 "validation error at byte {}: {}",
185 self.offset.0, self.kind
186 ),
187 }
188 }
189}
190
191impl fmt::Display for ValidationErrorKind {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 match self {
194 ValidationErrorKind::UnknownTypeIdx { idx } => {
195 write!(f, "unknown type index {}", idx.0)
196 }
197 ValidationErrorKind::UnknownFuncIdx { idx } => {
198 write!(f, "unknown function index {}", idx.0)
199 }
200 ValidationErrorKind::UndeclaredFuncRef { idx } => {
201 write!(f, "undeclared function reference {}", idx.0)
202 }
203 ValidationErrorKind::UnknownLocalIdx { idx } => {
204 write!(f, "unknown local index {}", idx.0)
205 }
206 ValidationErrorKind::UninitializedLocal { idx } => {
207 write!(f, "uninitialized local {}", idx.0)
208 }
209 ValidationErrorKind::UnknownGlobalIdx { idx, available } => {
210 write!(
211 f,
212 "unknown global index {} (available globals: {})",
213 idx.0, available
214 )
215 }
216 ValidationErrorKind::UnknownTableIdx { idx, available } => {
217 write!(
218 f,
219 "unknown table index {} (available tables: {})",
220 idx.0, available
221 )
222 }
223 ValidationErrorKind::UnknownMemIdx { idx, available } => {
224 write!(
225 f,
226 "unknown memory index {} (available memories: {})",
227 idx.0, available
228 )
229 }
230 ValidationErrorKind::UnknownDataIdx { idx, available } => {
231 write!(
232 f,
233 "unknown data index {} (available data segments: {})",
234 idx.0, available
235 )
236 }
237 ValidationErrorKind::UnknownElemIdx { idx, available } => {
238 write!(
239 f,
240 "unknown element index {} (available element segments: {})",
241 idx.0, available
242 )
243 }
244 ValidationErrorKind::InvalidMemArgAlign { op, max, found } => {
245 write!(
246 f,
247 "invalid memarg alignment in {}: found {}, maximum natural alignment exponent {}",
248 op, found, max
249 )
250 }
251 ValidationErrorKind::InvalidSimdLaneIdx { op, max, found } => {
252 write!(
253 f,
254 "invalid SIMD lane index in {}: found {}, maximum lane {}",
255 op, found, max
256 )
257 }
258 ValidationErrorKind::UnknownLabelIdx { idx } => {
259 write!(f, "unknown label index {}", idx.0)
260 }
261 ValidationErrorKind::Decode { context, kind } => {
262 write!(f, "instruction decode error in {}: {}", context, kind)
263 }
264 ValidationErrorKind::InvalidGlobalInitExpr => {
265 write!(f, "invalid global initializer expression")
266 }
267 ValidationErrorKind::NonConstantGlobalInitExpr => {
268 write!(f, "global initializer must be a constant expression")
269 }
270 ValidationErrorKind::MutableGlobalInInitExpr { idx } => {
271 write!(
272 f,
273 "global initializer references mutable imported global {}",
274 idx.0
275 )
276 }
277 ValidationErrorKind::ImmutableGlobalSet { idx } => {
278 write!(f, "cannot assign to immutable global {}", idx.0)
279 }
280 ValidationErrorKind::GlobalInitTypeMismatch { expected, found } => {
281 write!(
282 f,
283 "global initializer type mismatch: expected {:?}, found {:?}",
284 expected, found
285 )
286 }
287 ValidationErrorKind::BranchTypeMismatch {
288 label,
289 expected,
290 found,
291 } => {
292 write!(
293 f,
294 "branch to label {} has type mismatch: expected {:?}, found {:?}",
295 label.0, expected, found
296 )
297 }
298 ValidationErrorKind::InvalidBrOnNonNullTarget { label, found } => {
299 write!(
300 f,
301 "br_on_non_null target label {} must end in a reference type, found {:?}",
302 label.0, found
303 )
304 }
305 ValidationErrorKind::InconsistentBranchTypes { expected, found } => {
306 write!(
307 f,
308 "branch targets have inconsistent types: expected {:?}, found {:?}",
309 expected, found
310 )
311 }
312 ValidationErrorKind::UnexpectedElse => write!(f, "unexpected else"),
313 ValidationErrorKind::UnexpectedEnd => write!(f, "unexpected end"),
314 ValidationErrorKind::UnterminatedControlFrames => {
315 write!(f, "unterminated control frames")
316 }
317 ValidationErrorKind::ElseOutsideIf => write!(f, "else outside if block"),
318 ValidationErrorKind::MissingElseForResult => {
319 write!(f, "if block with result type requires else branch")
320 }
321 ValidationErrorKind::InvalidBlockType { block_type } => {
322 write!(f, "invalid block type {:?}", block_type)
323 }
324 ValidationErrorKind::ControlResultTypeMismatch { expected, found } => {
325 write!(
326 f,
327 "control frame result type mismatch: expected {:?}, found {:?}",
328 expected, found
329 )
330 }
331 ValidationErrorKind::InvalidSelectResultArity { found } => {
332 write!(
333 f,
334 "typed select requires exactly one result type, found {}",
335 found
336 )
337 }
338 ValidationErrorKind::SelectOperandTypeMismatch { expected, found } => {
339 write!(
340 f,
341 "select operands must match {:?}, found {:?}",
342 expected, found
343 )
344 }
345 ValidationErrorKind::StackUnderflow {
346 op,
347 expected,
348 available,
349 } => {
350 write!(
351 f,
352 "operand stack underflow in {}: expected {:?}, available {:?}",
353 op, expected, available
354 )
355 }
356 ValidationErrorKind::TypeMismatch {
357 op,
358 expected,
359 found,
360 } => {
361 write!(
362 f,
363 "type mismatch in {}: expected {:?}, found {:?}",
364 op, expected, found
365 )
366 }
367 ValidationErrorKind::FunctionResultTypeMismatch {
368 expected,
369 found,
370 full_stack,
371 } => {
372 write!(
373 f,
374 "function result type mismatch: expected {:?}, found {:?} at stack top (full stack {:?})",
375 expected, found, full_stack
376 )
377 }
378 ValidationErrorKind::ResultTypeMismatch { expected, found } => {
379 write!(
380 f,
381 "result type mismatch: expected {:?}, found {:?}",
382 expected, found
383 )
384 }
385 ValidationErrorKind::InvalidStartFunctionType { params, results } => {
386 write!(
387 f,
388 "start function must have type [] -> [], found {:?} -> {:?}",
389 params, results
390 )
391 }
392 ValidationErrorKind::InvalidElementExpr => {
393 write!(f, "invalid element initializer expression")
394 }
395 ValidationErrorKind::NonConstantElementExpr => {
396 write!(f, "element initializer must be a constant expression")
397 }
398 ValidationErrorKind::ElementExprTypeMismatch { expected, found } => {
399 write!(
400 f,
401 "element initializer type mismatch: expected {:?}, found {:?}",
402 expected, found
403 )
404 }
405 ValidationErrorKind::ElementTableTypeMismatch { expected, found } => {
406 write!(
407 f,
408 "active element segment table type mismatch: expected {:?}, found {:?}",
409 expected, found
410 )
411 }
412 ValidationErrorKind::InvalidCallIndirectTableType { expected, found } => {
413 write!(
414 f,
415 "call_indirect requires table element type {:?}, found {:?}",
416 expected, found
417 )
418 }
419 ValidationErrorKind::MissingDataCountSection { op } => {
420 write!(f, "{} requires a data count section", op)
421 }
422 ValidationErrorKind::MemorySizeOutOfRange => write!(f, "memory size"),
423 ValidationErrorKind::MemoryMinExceedsMax => {
424 write!(f, "size minimum must not be greater than maximum")
425 }
426 ValidationErrorKind::TableTypeMismatch => write!(f, "type mismatch"),
427 ValidationErrorKind::DuplicateExportName { name } => {
428 write!(f, "duplicate export name {:?}", name)
429 }
430 }
431 }
432}
433
434impl From<DecodeError> for ValidationErrorKind {
435 fn from(error: DecodeError) -> Self {
436 Self::Decode {
437 context: error.context,
438 kind: error.kind,
439 }
440 }
441}
442
443#[cfg(feature = "std")]
444impl std::error::Error for ValidationError {}
445
446#[cfg(not(feature = "std"))]
447impl core::error::Error for ValidationError {}