wasm/core/
error.rs

1use crate::validation_stack::ValidationStackEntry;
2use crate::RefType;
3use core::fmt::{Display, Formatter};
4use core::str::Utf8Error;
5
6use super::indices::FuncIdx;
7use crate::core::reader::section_header::SectionTy;
8use crate::core::reader::types::ValType;
9
10#[derive(Debug, PartialEq, Eq, Clone)]
11pub enum DecodingError {
12    /// The magic number at the start of the Wasm bytecode is invalid.
13    InvalidMagic,
14    /// The binary format version at the start of the Wasm bytecode is invalid.
15    InvalidBinaryFormatVersion,
16    /// The end of the binary file was reached unexpectedly.
17    Eof,
18
19    /// A UTF-8 string is malformed.
20    MalformedUtf8(Utf8Error),
21    /// The type of a section is malformed.
22    MalformedSectionTypeDiscriminator(u8),
23    /// The discriminator of a number type is malformed.
24    MalformedNumTypeDiscriminator(u8),
25    /// The discriminator of a vector type is malformed.
26    MalformedVecTypeDiscriminator(u8),
27    /// The discriminator of a function type is malformed.
28    MalformedFuncTypeDiscriminator(u8),
29    /// The discriminator of a reference type is malformed.
30    MalformedRefTypeDiscriminator(u8),
31    /// A valtype is malformed because it is neither a number, reference nor vector type.
32    MalformedValType,
33    /// The discriminator of an export description is malformed.
34    MalformedExportDescDiscriminator(u8),
35    /// The discriminator of an import description is malformed.
36    MalformedImportDescDiscriminator(u8),
37    /// The discriminator of a limits type is malformed.
38    MalformedLimitsDiscriminator(u8),
39    /// The min field of a limits type is larger than the max field.
40    MalformedLimitsMinLargerThanMax { min: u32, max: u32 },
41    /// The discriminator of a mut type is malformed.
42    MalformedMutDiscriminator(u8),
43    /// Block types use a special 33-bit signed integer for encoding type indices.
44    MalformedBlockTypeTypeIdx(i64),
45    /// A variable-length integer was read but it overflowed.
46    MalformedVariableLengthInteger,
47    /// The discriminator of an element kind is malformed.
48    MalformedElemKindDiscriminator(u8),
49    /// 33-bit signed integers are sometimes used to encode unsigned 32-bit
50    /// integers to prevent collisions between bit patterns of different types.
51    /// Therefore, 33-bit signed integers may never be negative.
52    I33IsNegative,
53    /// A function specifies too many locals, i.e. more than 2^32 - 1
54    TooManyLocals(u64),
55    /// The memory size specified by a mem type exceeds the maximum size.
56    MemoryTooLarge,
57}
58
59impl core::error::Error for DecodingError {}
60
61impl Display for DecodingError {
62    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
63        match self {
64            DecodingError::InvalidMagic => write!(f, "The magic number is invalid"),
65            DecodingError::InvalidBinaryFormatVersion => write!(f, "The Wasm binary format version is invalid"),
66            DecodingError::Eof => write!(f, "The end of the Wasm bytecode was reached unexpectedly"),
67            DecodingError::MalformedUtf8(utf8_error) => write!(f, "Failed to parse a UTF-8 string: {utf8_error}"),
68            DecodingError::MalformedSectionTypeDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a section type discriminator"),
69            DecodingError::MalformedNumTypeDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a number type discriminator"),
70            DecodingError::MalformedVecTypeDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a vector type discriminator"),
71            DecodingError::MalformedFuncTypeDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a function type discriminator"),
72            DecodingError::MalformedRefTypeDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a reference type discriminator"),
73            DecodingError::MalformedValType => write!(f, "Failed to read a value type because it is neither a number, reference or vector type"),
74            DecodingError::MalformedExportDescDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as an export description discriminator"),
75            DecodingError::MalformedImportDescDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as an import description discriminator"),
76            DecodingError::MalformedLimitsDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a limits type discriminator"),
77            DecodingError::MalformedLimitsMinLargerThanMax { min, max } => write!(f, "Limits are malformed because min={min} is larger than max={max}"),
78            DecodingError::MalformedMutDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as a mute type discriminator"),
79            DecodingError::MalformedBlockTypeTypeIdx(idx) => write!(f, "The type index {idx} which is encoded as a singed 33-bit integer inside a block type is malformed"),
80            DecodingError::MalformedVariableLengthInteger => write!(f, "Reading a variable-length integer overflowed"),
81            DecodingError::MalformedElemKindDiscriminator(byte) => write!(f, "Failed to parse {byte:#x} as an element kind discriminator"),
82            DecodingError::I33IsNegative => f.write_str("An i33 type is negative which is not allowed"),
83            DecodingError::TooManyLocals(n) => write!(f,"There are {n} locals and this exceeds the maximum allowed number of 2^32-1"),
84            DecodingError::MemoryTooLarge => write!(f, "The size specified by a memory type exceeds the maximum size"),
85        }
86    }
87}
88
89#[derive(Debug, PartialEq, Eq, Clone)]
90pub enum ValidationError {
91    Decoding(DecodingError),
92    /// An index for a type is invalid.
93    InvalidTypeIdx(u32),
94    /// An index for a function is invalid.
95    InvalidFuncIdx(u32),
96    /// An index for a table is invalid.
97    InvalidTableIdx(u32),
98    /// An index for a memory is invalid.
99    InvalidMemIdx(u32),
100    /// An index for a global is invalid.
101    InvalidGlobalIdx(u32),
102    /// An index for an element segment is invalid.
103    InvalidElemIdx(u32),
104    /// An index for a data segment is invalid.
105    InvalidDataIdx(u32),
106    /// An index for a local is invalid.
107    InvalidLocalIdx(u32),
108    /// An index for a label is invalid.
109    InvalidLabelIdx(u32),
110    /// An index for a lane of some vector type is invalid.
111    InvalidLaneIdx(u8),
112
113    /// A section with given type is out of order. All section types have a fixed order in which they must occur.
114    SectionOutOfOrder(SectionTy),
115    /// A custom section contains more bytes than its section header specifies.
116    InvalidCustomSectionLength,
117    ExprMissingEnd,
118    InvalidInstr(u8),
119    InvalidMultiByteInstr(u8, u32),
120    EndInvalidValueStack,
121    InvalidValidationStackValType(Option<ValType>),
122    InvalidValidationStackType(ValidationStackEntry),
123    ExpectedAnOperand,
124    /// An attempt has been made to mutate a const global
125    MutationOfConstGlobal,
126    /// An alignment of some memory instruction is invalid
127    ErroneousAlignment {
128        alignment: u32,
129        minimum_required_alignment: u32,
130    },
131    /// The validation control stack is empty, even though an entry was expected.
132    // TODO Reconsider if we want to expose this error. It should probably never happen and thus also never bubble up to the user.
133    ValidationCtrlStackEmpty,
134    /// An `else` instruction was found while not inside an `if` block.
135    ElseWithoutMatchingIf,
136    /// An `end` for a matching `if` instruction was found, but there was no `else` instruction in between.
137    IfWithoutMatchingElse,
138    /// A `table.init` instruction specified a table and an element segment that store different reference types.
139    MismatchedRefTypesDuringTableInit {
140        table_ty: RefType,
141        elem_ty: RefType,
142    },
143    /// A `table.copy` instruction referenced two tables that store different reference types.
144    MismatchedRefTypesDuringTableCopy {
145        source_table_ty: RefType,
146        destination_table_ty: RefType,
147    },
148    /// An expected reference type did not match the actual reference type on the validation stack.
149    MismatchedRefTypesOnValidationStack {
150        expected: RefType,
151        actual: RefType,
152    },
153    /// An indirect call to a table with does not store function references was made.
154    IndirectCallToNonFuncRefTable(RefType),
155    /// A reference type was expected to be on the stack, but a value type was found.
156    ExpectedReferenceTypeOnStack(ValType),
157    /// When a is referenced in the code section it must be contained in `C.refs`, which was not the case
158    ReferencingAnUnreferencedFunction(FuncIdx),
159    /// The select instructions may work with multiple values in the future. However, as of now its vector may only have one element.
160    InvalidSelectTypeVectorLength(usize),
161    /// Multiple exports share the same name
162    DuplicateExportName,
163    /// Multiple memories are not yet allowed without the proposal.
164    UnsupportedMultipleMemoriesProposal,
165    /// An expr in the code section has trailing instructions following its `end` instruction.
166    CodeExprHasTrailingInstructions,
167    /// The lengths of the function and code sections must match.
168    FunctionAndCodeSectionsHaveDifferentLengths,
169    /// The data count specified in the data count section and the length of the data section must match.
170    DataCountAndDataSectionsLengthAreDifferent,
171    InvalidImportType,
172    /// The function signature of the start function is invalid. It must not specify any parameters or return values.
173    InvalidStartFunctionSignature,
174    /// An active element segment's type and its table's type are different.
175    ActiveElementSegmentTypeMismatch,
176    /// The data count section is required, if there are instructions that use
177    /// data indices.
178    MissingDataCountSection,
179    /// The mode of a data segment was invalid. Only values in the range 0..=2
180    /// are allowed.
181    InvalidDataSegmentMode(u32),
182    /// The mode of an element was invalid. Only values in the range 0..=7 are
183    /// allowed.
184    InvalidElementMode(u32),
185    /// The module contains too many functions, i.e. imported or locally-defined
186    /// functions. The maximum number of functions is [`u32::MAX`].
187    TooManyFunctions,
188    /// The module contains too many tables, i.e. imported or locally-defined
189    /// tables. The maximum number of tables is [`u32::MAX`].
190    TooManyTables,
191    /// The module contains too many memories, i.e. imported or locally-defined
192    /// memories. The maximum number of memories is [`u32::MAX`].
193    TooManyMemories,
194    /// The module contains too many globals, i.e. imported or locally-defined
195    /// globals. The maximum number of memories is [`u32::MAX`].
196    TooManyGlobals,
197}
198
199impl core::error::Error for ValidationError {}
200
201impl Display for ValidationError {
202    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
203        match self {
204            ValidationError::Decoding(err) => write!(f, "Decoding failed: {err}"),
205
206            ValidationError::InvalidTypeIdx(idx) => write!(f, "The type index {idx} is invalid"),
207            ValidationError::InvalidFuncIdx(idx) => write!(f, "The function index {idx} is invalid"),
208            ValidationError::InvalidTableIdx(idx) => write!(f, "The table index {idx} is invalid"),
209            ValidationError::InvalidMemIdx(idx) => write!(f, "The memory index {idx} is invalid"),
210            ValidationError::InvalidGlobalIdx(idx) => write!(f, "The global index {idx} is invalid"),
211            ValidationError::InvalidElemIdx(idx) => write!(f, "The element segment index {idx} is invalid"),
212            ValidationError::InvalidDataIdx(idx) => write!(f, "The data segment index {idx} is invalid"),
213            ValidationError::InvalidLocalIdx(idx) => write!(f, "The local index {idx} is invalid"),
214            ValidationError::InvalidLabelIdx(idx) => write!(f, "The label index {idx} is invalid"),
215            ValidationError::InvalidLaneIdx(idx) => write!(f, "The lane index {idx} is invalid"),
216
217            ValidationError::SectionOutOfOrder(ty) => write!(f, "A section of type `{ty:?}` is defined out of order"),
218            ValidationError::InvalidCustomSectionLength => write!(f, "A custom section contains more bytes than its section header specifies"),
219            ValidationError::ExprMissingEnd => write!(f, "An expr type is missing an end byte"),
220            ValidationError::InvalidInstr(byte) => write!(f, "The instruction opcode {byte:#x} is invalid"),
221            ValidationError::InvalidMultiByteInstr(first_byte, second_instr) => write!(f, "The multi-byte instruction opcode {first_byte:#x} {second_instr} is invalid"),
222            ValidationError::ActiveElementSegmentTypeMismatch => write!(f, "an element segment's type and its table's type are different"),
223            ValidationError::EndInvalidValueStack => write!(f, "Different value stack types were expected at the end of a block/function"),
224            ValidationError::InvalidValidationStackValType(ty) => write!(f, "An unexpected type `{ty:?}` was found on the stack when trying to pop another"),
225            ValidationError::InvalidValidationStackType(ty) => write!(f, "An unexpected type `{ty:?}` was found on the stack"),
226            ValidationError::ExpectedAnOperand => write!(f, "Expected a value type operand on the stack"),
227            ValidationError::MutationOfConstGlobal => write!(f, "An attempt has been made to mutate a const global"),
228            ValidationError::ErroneousAlignment {alignment , minimum_required_alignment} => write!(f, "The alignment 2^{alignment} is not less or equal to the required alignment 2^{minimum_required_alignment}"),
229            ValidationError::ValidationCtrlStackEmpty => write!(f, "Failed to retrieve last ctrl block because validation ctrl stack is empty"),
230            ValidationError::ElseWithoutMatchingIf => write!(f, "Found `else` without a previous matching `if` instruction"),
231            ValidationError::IfWithoutMatchingElse => write!(f, "Found `end` without a previous matching `else` to an `if` instruction"),
232            ValidationError::MismatchedRefTypesDuringTableInit { table_ty, elem_ty } => write!(f, "Mismatch of table type `{table_ty:?}` and element segment type `{elem_ty:?}` for `table.init` instruction"),
233            ValidationError::MismatchedRefTypesDuringTableCopy { source_table_ty, destination_table_ty } => write!(f, "Mismatch of source table type `{source_table_ty:?}` and destination table type `{destination_table_ty:?}` for `table.copy` instruction"),
234            ValidationError::MismatchedRefTypesOnValidationStack { expected, actual } => write!(f, "Mismatch of reference types on the value stack: Expected `{expected:?}` but got `{actual:?}`"),
235            ValidationError::IndirectCallToNonFuncRefTable(table_ty) => write!(f, "An indirect call to a table which does not store function references but instead `{table_ty:?}` was made"),
236            ValidationError::ExpectedReferenceTypeOnStack(found_valtype) => write!(f, "Expected a reference type but instead found a `{found_valtype:?}` on the stack"),
237            ValidationError::ReferencingAnUnreferencedFunction(func_idx) => write!(f, "Referenced a function with index {func_idx} that was not referenced in prior validation"),
238            ValidationError::InvalidSelectTypeVectorLength(len) => write!(f, "The type vector of a `select` instruction must be of length 1 as of now but it is of length {len} instead"),
239            ValidationError::DuplicateExportName => write!(f,"Multiple exports share the same name"),
240            ValidationError::UnsupportedMultipleMemoriesProposal => write!(f,"A memory index other than 1 was used, but the proposal for multiple memories is not yet supported"),
241            ValidationError::CodeExprHasTrailingInstructions => write!(f,"A code expression has invalid trailing instructions following its `end` instruction"),
242            ValidationError::FunctionAndCodeSectionsHaveDifferentLengths => write!(f,"The function and code sections have different lengths"),
243            ValidationError::DataCountAndDataSectionsLengthAreDifferent => write!(f,"The data count section specifies a different length than there are data segments in the data section"),
244            ValidationError::InvalidImportType => f.write_str("Invalid import type"),
245            ValidationError::InvalidStartFunctionSignature => write!(f,"The start function has parameters or return types which it is not allowed to have"),
246            ValidationError::MissingDataCountSection => f.write_str("Some instructions could not be validated because the data count section is missing"),
247            ValidationError::InvalidDataSegmentMode(mode) => write!(f, "The mode of a data segment was invalid (only 0..=2 is allowed): {mode}"),
248            ValidationError::InvalidElementMode(mode) => write!(f, "The mode of an element was invalid (only 0..=7 is allowed): {mode}"),
249            ValidationError::TooManyFunctions => f.write_str("The module contains too many functions. The maximum number of functions (either imported or locally-defined) is 2^32 - 1"),
250            ValidationError::TooManyTables => f.write_str("The module contains too many tables. The maximum number of tables (either imported or locally-defined) is 2^32 - 1"),
251            ValidationError::TooManyMemories => f.write_str("The module contains too many memories. The maximum number of memories (either imported or locally-defined) is 2^32 - 1"),
252            ValidationError::TooManyGlobals => f.write_str("The module contains too many globals. The maximum number of globals (either imported or locally-defined) is 2^32 - 1"),
253        }
254    }
255}
256
257impl ValidationError {
258    /// Convert this error to a message that is compatible with the error messages used by the official Wasm testsuite.
259    pub fn to_message(&self) -> &'static str {
260        todo!("convert validation error to testsuite message");
261    }
262}
263
264impl From<DecodingError> for ValidationError {
265    fn from(error: DecodingError) -> Self {
266        Self::Decoding(error)
267    }
268}
269
270#[cfg(test)]
271mod test {
272    use alloc::string::ToString;
273
274    use crate::core::error::DecodingError;
275
276    #[test]
277    fn fmt_invalid_magic() {
278        assert!(DecodingError::InvalidMagic
279            .to_string()
280            .contains("magic number"));
281    }
282
283    #[test]
284    fn fmt_invalid_version() {
285        assert!(DecodingError::InvalidBinaryFormatVersion
286            .to_string()
287            .contains("version"));
288    }
289}