wasm/core/
error.rs

1use alloc::format;
2use alloc::string::{String, ToString};
3
4use crate::core::indices::GlobalIdx;
5use crate::validation_stack::ValidationStackEntry;
6use crate::RefType;
7use core::fmt::{Display, Formatter};
8use core::str::Utf8Error;
9
10use crate::core::reader::section_header::SectionTy;
11use crate::core::reader::types::ValType;
12
13use super::indices::{DataIdx, ElemIdx, FuncIdx, MemIdx, TableIdx, TypeIdx};
14
15#[derive(Debug, PartialEq, Eq, Clone)]
16pub enum RuntimeError {
17    DivideBy0,
18    UnrepresentableResult,
19    FunctionNotFound,
20    // https://github.com/wasmi-labs/wasmi/blob/37d1449524a322817c55026eb21eb97dd693b9ce/crates/core/src/trap.rs#L265C5-L265C27
21    BadConversionToInteger,
22    MemoryAccessOutOfBounds,
23    TableAccessOutOfBounds,
24    ElementAccessOutOfBounds,
25    UninitializedElement,
26    SignatureMismatch,
27    ExpectedAValueOnTheStack,
28    ModuleNotFound,
29    UnmetImport,
30    UndefinedTableIndex,
31    // "undefined element" <- as-call_indirect-last
32    ReachedUnreachable,
33    StackExhaustion,
34}
35
36#[derive(Debug, PartialEq, Eq, Clone)]
37pub enum Proposal {
38    Memory64,
39    MultipleMemories,
40    Threads,
41}
42
43#[derive(Debug, PartialEq, Eq, Clone)]
44pub enum StoreInstantiationError {
45    ActiveDataWriteOutOfBounds,
46    I64ValueOutOfReach(String),
47    MissingValueOnTheStack,
48    TooManyMemories(usize),
49}
50
51#[derive(Debug, PartialEq, Eq, Clone)]
52pub enum LinkerError {
53    UnmetImport,
54}
55
56#[derive(Debug, PartialEq, Eq, Clone)]
57pub enum Error {
58    /// The magic number at the very start of the given WASM file is invalid.
59    InvalidMagic,
60    InvalidVersion,
61    MalformedUtf8String(Utf8Error),
62    Eof,
63    InvalidSection(SectionTy, String),
64    InvalidSectionType(u8),
65    SectionOutOfOrder(SectionTy),
66    InvalidNumType,
67    InvalidVecType,
68    InvalidFuncType,
69    InvalidFuncTypeIdx,
70    InvalidRefType,
71    InvalidValType,
72    InvalidExportDesc(u8),
73    InvalidImportDesc(u8),
74    ExprMissingEnd,
75    InvalidInstr(u8),
76    InvalidMultiByteInstr(u8, u32),
77    EndInvalidValueStack,
78    InvalidLocalIdx,
79    InvalidValidationStackValType(Option<ValType>),
80    InvalidValidationStackType(ValidationStackEntry),
81    ExpectedAnOperand,
82    InvalidLimitsType(u8),
83    InvalidMutType(u8),
84    MoreThanOneMemory,
85    InvalidLimit,
86    MemSizeTooBig,
87    InvalidGlobalIdx(GlobalIdx),
88    GlobalIsConst,
89    RuntimeError(RuntimeError),
90    MemoryIsNotDefined(MemIdx),
91    //           mem.align, wanted alignment
92    ErroneousAlignment(u32, u32),
93    NoDataSegments,
94    DataSegmentNotFound(DataIdx),
95    InvalidLabelIdx(usize),
96    ValidationCtrlStackEmpty,
97    ElseWithoutMatchingIf,
98    IfWithoutMatchingElse,
99    UnknownTable,
100    TableIsNotDefined(TableIdx),
101    ElementIsNotDefined(ElemIdx),
102    DifferentRefTypes(RefType, RefType),
103    ExpectedARefType(ValType),
104    WrongRefTypeForInteropValue(RefType, RefType),
105    FunctionIsNotDefined(FuncIdx),
106    ReferencingAnUnreferencedFunction(FuncIdx),
107    FunctionTypeIsNotDefined(TypeIdx),
108    StoreInstantiationError(StoreInstantiationError),
109    OnlyFuncRefIsAllowed,
110    TypeUnificationMismatch,
111    InvalidSelectTypeVector,
112    TooManyLocals(usize),
113    UnsupportedProposal(Proposal),
114    Overflow,
115    LinkerError(LinkerError),
116    UnknownFunction,
117    UnknownMemory,
118    UnknownGlobal,
119    UnknownImport, // TODO refactor
120    DuplicateExportName,
121    InvalidImportType,
122}
123
124impl Display for Error {
125    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
126        match self {
127            Error::InvalidMagic => {
128                f.write_str("The magic number at the very start of the given WASM file is invalid.")
129            }
130            Error::InvalidVersion => f.write_str("The version in the WASM file header is invalid"),
131            Error::MalformedUtf8String(err) => f.write_fmt(format_args!(
132                "A name could not be parsed as it was invalid UTF8: {err}"
133            )),
134            Error::Eof => f.write_str(
135                "A value was expected in the WASM binary but the end of file was reached instead",
136            ),
137            Error::InvalidSection(section, reason) => f.write_fmt(format_args!(
138                "Section '{:?}' invalid! Reason: {}",
139                section, reason
140            )),
141            Error::InvalidSectionType(ty) => f.write_fmt(format_args!(
142                "An invalid section type id was found in a section header: {ty}"
143            )),
144            Error::SectionOutOfOrder(ty) => {
145                f.write_fmt(format_args!("The section {ty:?} is out of order"))
146            }
147            Error::InvalidNumType => {
148                f.write_str("An invalid byte was read where a numtype was expected")
149            }
150            Error::InvalidVecType => {
151                f.write_str("An invalid byte was read where a vectype was expected")
152            }
153            Error::InvalidFuncType => {
154                f.write_str("An invalid byte was read where a functype was expected")
155            }
156            Error::InvalidFuncTypeIdx => {
157                f.write_str("An invalid index to the fuctypes table was read")
158            }
159            Error::InvalidRefType => {
160                f.write_str("An invalid byte was read where a reftype was expected")
161            }
162            Error::InvalidValType => {
163                f.write_str("An invalid byte was read where a valtype was expected")
164            }
165            Error::InvalidExportDesc(byte) => f.write_fmt(format_args!(
166                "An invalid byte `{byte:#x?}` was read where an exportdesc was expected"
167            )),
168            Error::InvalidImportDesc(byte) => f.write_fmt(format_args!(
169                "An invalid byte `{byte:#x?}` was read where an importdesc was expected"
170            )),
171            Error::ExprMissingEnd => f.write_str("An expr is missing an end byte"),
172            Error::InvalidInstr(byte) => f.write_fmt(format_args!(
173                "An invalid instruction opcode was found: `{byte:#x?}`"
174            )),
175            Error::InvalidMultiByteInstr(byte1, byte2) => f.write_fmt(format_args!(
176                "An invalid multi-byte instruction opcode was found: `{byte1:#x?} {byte2:#x?}`"
177            )),
178            Error::EndInvalidValueStack => f.write_str(
179                "Different value stack types were expected at the end of a block/function.",
180            ),
181            Error::InvalidLocalIdx => f.write_str("An invalid localidx was used"),
182            Error::InvalidValidationStackValType(ty) => f.write_fmt(format_args!(
183                "An unexpected type was found on the stack when trying to pop another: `{ty:?}`"
184            )),
185            Error::InvalidValidationStackType(ty) => f.write_fmt(format_args!(
186                "An unexpected type was found on the stack: `{ty:?}`"
187            )),
188            Error::InvalidLimitsType(ty) => {
189                f.write_fmt(format_args!("An invalid limits type was found: {ty:#x?}"))
190            }
191            Error::InvalidMutType(byte) => f.write_fmt(format_args!(
192                "An invalid mut/const byte was found: {byte:#x?}"
193            )),
194            Error::MoreThanOneMemory => {
195                f.write_str("As of not only one memory is allowed per module.")
196            }
197            Error::InvalidLimit => f.write_str("Size minimum must not be greater than maximum"),
198            Error::MemSizeTooBig => f.write_str("Memory size must be at most 65536 pages (4GiB)"),
199            Error::InvalidGlobalIdx(idx) => f.write_fmt(format_args!(
200                "An invalid global index `{idx}` was specified"
201            )),
202            Error::GlobalIsConst => f.write_str("A const global cannot be written to"),
203            Error::RuntimeError(err) => err.fmt(f),
204            Error::ExpectedAnOperand => f.write_str("Expected a ValType"), // Error => f.write_str("Expected an operand (ValType) on the stack")
205            Error::MemoryIsNotDefined(memidx) => f.write_fmt(format_args!(
206                "C.mems[{}] is NOT defined when it should be",
207                memidx
208            )),
209            Error::ErroneousAlignment(mem_align, minimum_wanted_alignment) => {
210                f.write_fmt(format_args!(
211                    "Alignment ({}) is not less or equal to {}",
212                    mem_align, minimum_wanted_alignment
213                ))
214            }
215            Error::NoDataSegments => f.write_str("Data Count is None"),
216            Error::DataSegmentNotFound(data_idx) => {
217                f.write_fmt(format_args!("Data Segment {} not found", data_idx))
218            }
219            Error::InvalidLabelIdx(label_idx) => {
220                f.write_fmt(format_args!("invalid label index {}", label_idx))
221            }
222            Error::ValidationCtrlStackEmpty => {
223                f.write_str("cannot retrieve last ctrl block, validation ctrl stack is empty")
224            }
225            Error::ElseWithoutMatchingIf => {
226                f.write_str("read 'else' without a previous matching 'if' instruction")
227            }
228            Error::IfWithoutMatchingElse => {
229                f.write_str("read 'end' without matching 'else' instruction to 'if' instruction")
230            }
231            Error::TableIsNotDefined(table_idx) => f.write_fmt(format_args!(
232                "C.tables[{}] is NOT defined when it should be",
233                table_idx
234            )),
235            Error::ElementIsNotDefined(elem_idx) => f.write_fmt(format_args!(
236                "C.elems[{}] is NOT defined when it should be",
237                elem_idx
238            )),
239            Error::DifferentRefTypes(rref1, rref2) => f.write_fmt(format_args!(
240                "RefType {:?} is NOT equal to RefType {:?}",
241                rref1, rref2
242            )),
243            Error::ExpectedARefType(found_valtype) => f.write_fmt(format_args!(
244                "Expected a RefType, found a {:?} instead",
245                found_valtype
246            )),
247            Error::WrongRefTypeForInteropValue(ref_given, ref_wanted) => f.write_fmt(format_args!(
248                "Wrong RefType for InteropValue: Given {:?} - Needed {:?}",
249                ref_given, ref_wanted
250            )),
251            Error::FunctionIsNotDefined(func_idx) => f.write_fmt(format_args!(
252                "C.functions[{}] is NOT defined when it should be",
253                func_idx
254            )),
255            Error::ReferencingAnUnreferencedFunction(func_idx) => f.write_fmt(format_args!(
256                "Referenced a function ({}) that was not referenced in validation",
257                func_idx
258            )),
259            Error::FunctionTypeIsNotDefined(func_ty_idx) => f.write_fmt(format_args!(
260                "C.fn_types[{}] is NOT defined when it should be",
261                func_ty_idx
262            )),
263            Error::StoreInstantiationError(err) => err.fmt(f),
264            Error::OnlyFuncRefIsAllowed => f.write_str("Only FuncRef is allowed"),
265            Error::TypeUnificationMismatch => {
266                f.write_str("cannot unify types")
267            }
268            Error::InvalidSelectTypeVector => {
269                f.write_str("SELECT T* (0x1C) instruction must have exactly one type in the subsequent type vector")
270            }
271            Error::TooManyLocals(x) => {
272                f.write_fmt(format_args!("Too many locals (more than 2^32-1): {}", x))
273            }
274            Error::UnsupportedProposal(proposal) => {
275                f.write_fmt(format_args!("Unsupported proposal: {:?}", proposal))
276            }
277            Error::Overflow => f.write_str("Overflow"),
278            Error::LinkerError(err) => err.fmt(f),
279
280            // TODO: maybe move these to LinkerError also add more info to them (the name's export, function idx, etc)
281            Error::UnknownFunction => f.write_str("Unknown function"),
282            Error::UnknownMemory => f.write_str("Unknown memory"),
283            Error::UnknownGlobal => f.write_str("Unknown global"),
284            Error::UnknownTable => f.write_str("Unknown table"),
285            Error::DuplicateExportName => f.write_str("Duplicate export name"),
286            Error::InvalidImportType => f.write_str("Invalid import type"),
287            // TODO: maybe move these to LinkerError also add more info to them (the name's export, function idx, etc)
288            Error::UnknownImport => f.write_str("Unknown Import"),
289
290        }
291    }
292}
293
294impl Display for RuntimeError {
295    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
296        match self {
297            RuntimeError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
298            RuntimeError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
299            RuntimeError::FunctionNotFound => f.write_str("Function not found"),
300            RuntimeError::BadConversionToInteger => f.write_str("Bad conversion to integer"),
301            RuntimeError::MemoryAccessOutOfBounds => f.write_str("Memory access out of bounds"),
302            RuntimeError::TableAccessOutOfBounds => f.write_str("Table access out of bounds"),
303            RuntimeError::ElementAccessOutOfBounds => f.write_str("Element access out of bounds"),
304            RuntimeError::UninitializedElement => f.write_str("Uninitialized element"),
305            RuntimeError::SignatureMismatch => f.write_str("Indirect call signature mismatch"),
306            RuntimeError::ExpectedAValueOnTheStack => {
307                f.write_str("Expected a value on the stack, but None was found")
308            }
309            RuntimeError::ModuleNotFound => f.write_str("No such module exists"),
310            RuntimeError::UnmetImport => {
311                f.write_str("There is at least one import which has no corresponding export")
312            }
313            RuntimeError::UndefinedTableIndex => {
314                f.write_str("Indirect call: table index out of bounds")
315            }
316            RuntimeError::ReachedUnreachable => {
317                f.write_str("an unreachable statement was reached, triggered a trap")
318            }
319            RuntimeError::StackExhaustion => {
320                f.write_str("either the call stack or the value stack overflowed")
321            }
322        }
323    }
324}
325
326impl Display for StoreInstantiationError {
327    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
328        use StoreInstantiationError::*;
329        match self {
330            ActiveDataWriteOutOfBounds => {
331                f.write_str("Active data writing in memory is out of bounds")
332            }
333            I64ValueOutOfReach(s) => f.write_fmt(format_args!(
334                "I64 value {}is out of reach",
335                if !s.is_empty() {
336                    format!("for {s} ")
337                } else {
338                    "".to_string()
339                }
340            )),
341            MissingValueOnTheStack => f.write_str(""),
342            TooManyMemories(x) => f.write_fmt(format_args!("Too many memories (overflow): {}", x)),
343        }
344    }
345}
346
347impl Display for LinkerError {
348    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
349        use LinkerError::*;
350        match self {
351            UnmetImport => f.write_str("Unmet import"),
352        }
353    }
354}
355
356pub type Result<T> = core::result::Result<T, Error>;
357
358impl From<RuntimeError> for Error {
359    fn from(value: RuntimeError) -> Self {
360        Self::RuntimeError(value)
361    }
362}
363
364impl From<StoreInstantiationError> for Error {
365    fn from(value: StoreInstantiationError) -> Self {
366        Self::StoreInstantiationError(value)
367    }
368}