wasm/core/
error.rs

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