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    HostFunctionSignatureMismatch,
35}
36
37#[derive(Debug, PartialEq, Eq, Clone)]
38pub enum Proposal {
39    Memory64,
40    MultipleMemories,
41    Threads,
42}
43
44#[derive(Debug, PartialEq, Eq, Clone)]
45pub enum StoreInstantiationError {
46    ActiveDataWriteOutOfBounds,
47    I64ValueOutOfReach(String),
48    MissingValueOnTheStack,
49    TooManyMemories(usize),
50}
51
52#[derive(Debug, PartialEq, Eq, Clone)]
53pub enum LinkerError {
54    UnmetImport,
55}
56
57#[derive(Debug, PartialEq, Eq, Clone)]
58pub enum Error {
59    /// The magic number at the very start of the given WASM file is invalid.
60    InvalidMagic,
61    InvalidVersion,
62    MalformedUtf8String(Utf8Error),
63    Eof,
64    InvalidSection(SectionTy, String),
65    InvalidSectionType(u8),
66    SectionOutOfOrder(SectionTy),
67    InvalidNumType,
68    InvalidVecType,
69    InvalidFuncType,
70    InvalidFuncTypeIdx,
71    InvalidRefType,
72    InvalidValType,
73    InvalidExportDesc(u8),
74    InvalidImportDesc(u8),
75    ExprMissingEnd,
76    InvalidInstr(u8),
77    InvalidMultiByteInstr(u8, u32),
78    EndInvalidValueStack,
79    InvalidLocalIdx,
80    InvalidValidationStackValType(Option<ValType>),
81    InvalidValidationStackType(ValidationStackEntry),
82    ExpectedAnOperand,
83    InvalidLimitsType(u8),
84    InvalidMutType(u8),
85    MoreThanOneMemory,
86    InvalidLimit,
87    MemSizeTooBig,
88    InvalidGlobalIdx(GlobalIdx),
89    GlobalIsConst,
90    RuntimeError(RuntimeError),
91    MemoryIsNotDefined(MemIdx),
92    //           mem.align, wanted alignment
93    ErroneousAlignment(u32, u32),
94    NoDataSegments,
95    DataSegmentNotFound(DataIdx),
96    InvalidLabelIdx(usize),
97    ValidationCtrlStackEmpty,
98    ElseWithoutMatchingIf,
99    IfWithoutMatchingElse,
100    UnknownTable,
101    TableIsNotDefined(TableIdx),
102    ElementIsNotDefined(ElemIdx),
103    DifferentRefTypes(RefType, RefType),
104    ExpectedARefType(ValType),
105    WrongRefTypeForInteropValue(RefType, RefType),
106    FunctionIsNotDefined(FuncIdx),
107    ReferencingAnUnreferencedFunction(FuncIdx),
108    FunctionTypeIsNotDefined(TypeIdx),
109    StoreInstantiationError(StoreInstantiationError),
110    OnlyFuncRefIsAllowed,
111    TypeUnificationMismatch,
112    InvalidSelectTypeVector,
113    TooManyLocals(usize),
114    UnsupportedProposal(Proposal),
115    Overflow,
116    LinkerError(LinkerError),
117    UnknownFunction,
118    UnknownMemory,
119    UnknownGlobal,
120    UnknownImport, // TODO refactor
121    DuplicateExportName,
122    InvalidImportType,
123}
124
125impl Display for Error {
126    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
127        match self {
128            Error::InvalidMagic => {
129                f.write_str("The magic number at the very start of the given WASM file is invalid.")
130            }
131            Error::InvalidVersion => f.write_str("The version in the WASM file header is invalid"),
132            Error::MalformedUtf8String(err) => f.write_fmt(format_args!(
133                "A name could not be parsed as it was invalid UTF8: {err}"
134            )),
135            Error::Eof => f.write_str(
136                "A value was expected in the WASM binary but the end of file was reached instead",
137            ),
138            Error::InvalidSection(section, reason) => f.write_fmt(format_args!(
139                "Section '{section:?}' invalid! Reason: {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[{memidx}] is NOT defined when it should be"
207            )),
208            Error::ErroneousAlignment(mem_align, minimum_wanted_alignment) => {
209                f.write_fmt(format_args!(
210                    "Alignment ({mem_align}) is not less or equal to {minimum_wanted_alignment}"
211                ))
212            }
213            Error::NoDataSegments => f.write_str("Data Count is None"),
214            Error::DataSegmentNotFound(data_idx) => {
215                f.write_fmt(format_args!("Data Segment {data_idx} not found"))
216            }
217            Error::InvalidLabelIdx(label_idx) => {
218                f.write_fmt(format_args!("invalid label index {label_idx}"))
219            }
220            Error::ValidationCtrlStackEmpty => {
221                f.write_str("cannot retrieve last ctrl block, validation ctrl stack is empty")
222            }
223            Error::ElseWithoutMatchingIf => {
224                f.write_str("read 'else' without a previous matching 'if' instruction")
225            }
226            Error::IfWithoutMatchingElse => {
227                f.write_str("read 'end' without matching 'else' instruction to 'if' instruction")
228            }
229            Error::TableIsNotDefined(table_idx) => f.write_fmt(format_args!(
230                "C.tables[{table_idx}] is NOT defined when it should be"
231            )),
232            Error::ElementIsNotDefined(elem_idx) => f.write_fmt(format_args!(
233                "C.elems[{elem_idx}] is NOT defined when it should be"
234            )),
235            Error::DifferentRefTypes(rref1, rref2) => f.write_fmt(format_args!(
236                "RefType {rref1:?} is NOT equal to RefType {rref2:?}"
237            )),
238            Error::ExpectedARefType(found_valtype) => f.write_fmt(format_args!(
239                "Expected a RefType, found a {found_valtype:?} instead"
240            )),
241            Error::WrongRefTypeForInteropValue(ref_given, ref_wanted) => f.write_fmt(format_args!(
242                "Wrong RefType for InteropValue: Given {ref_given:?} - Needed {ref_wanted:?}"
243            )),
244            Error::FunctionIsNotDefined(func_idx) => f.write_fmt(format_args!(
245                "C.functions[{func_idx}] is NOT defined when it should be"
246            )),
247            Error::ReferencingAnUnreferencedFunction(func_idx) => f.write_fmt(format_args!(
248                "Referenced a function ({func_idx}) that was not referenced in validation"
249            )),
250            Error::FunctionTypeIsNotDefined(func_ty_idx) => f.write_fmt(format_args!(
251                "C.fn_types[{func_ty_idx}] is NOT defined when it should be"
252            )),
253            Error::StoreInstantiationError(err) => err.fmt(f),
254            Error::OnlyFuncRefIsAllowed => f.write_str("Only FuncRef is allowed"),
255            Error::TypeUnificationMismatch => {
256                f.write_str("cannot unify types")
257            }
258            Error::InvalidSelectTypeVector => {
259                f.write_str("SELECT T* (0x1C) instruction must have exactly one type in the subsequent type vector")
260            }
261            Error::TooManyLocals(x) => {
262                f.write_fmt(format_args!("Too many locals (more than 2^32-1): {x}"))
263            }
264            Error::UnsupportedProposal(proposal) => {
265                f.write_fmt(format_args!("Unsupported proposal: {proposal:?}"))
266            }
267            Error::Overflow => f.write_str("Overflow"),
268            Error::LinkerError(err) => err.fmt(f),
269
270            // TODO: maybe move these to LinkerError also add more info to them (the name's export, function idx, etc)
271            Error::UnknownFunction => f.write_str("Unknown function"),
272            Error::UnknownMemory => f.write_str("Unknown memory"),
273            Error::UnknownGlobal => f.write_str("Unknown global"),
274            Error::UnknownTable => f.write_str("Unknown table"),
275            Error::DuplicateExportName => f.write_str("Duplicate export name"),
276            Error::InvalidImportType => f.write_str("Invalid import type"),
277            // TODO: maybe move these to LinkerError also add more info to them (the name's export, function idx, etc)
278            Error::UnknownImport => f.write_str("Unknown Import"),
279
280        }
281    }
282}
283
284impl Display for RuntimeError {
285    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
286        match self {
287            RuntimeError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
288            RuntimeError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
289            RuntimeError::FunctionNotFound => f.write_str("Function not found"),
290            RuntimeError::BadConversionToInteger => f.write_str("Bad conversion to integer"),
291            RuntimeError::MemoryAccessOutOfBounds => f.write_str("Memory access out of bounds"),
292            RuntimeError::TableAccessOutOfBounds => f.write_str("Table access out of bounds"),
293            RuntimeError::ElementAccessOutOfBounds => f.write_str("Element access out of bounds"),
294            RuntimeError::UninitializedElement => f.write_str("Uninitialized element"),
295            RuntimeError::SignatureMismatch => f.write_str("Indirect call signature mismatch"),
296            RuntimeError::ExpectedAValueOnTheStack => {
297                f.write_str("Expected a value on the stack, but None was found")
298            }
299            RuntimeError::ModuleNotFound => f.write_str("No such module exists"),
300            RuntimeError::UnmetImport => {
301                f.write_str("There is at least one import which has no corresponding export")
302            }
303            RuntimeError::UndefinedTableIndex => {
304                f.write_str("Indirect call: table index out of bounds")
305            }
306            RuntimeError::ReachedUnreachable => {
307                f.write_str("an unreachable statement was reached, triggered a trap")
308            }
309            RuntimeError::StackExhaustion => {
310                f.write_str("either the call stack or the value stack overflowed")
311            }
312            RuntimeError::HostFunctionSignatureMismatch => {
313                f.write_str("host function call did not respect its type signature")
314            }
315        }
316    }
317}
318
319impl Display for StoreInstantiationError {
320    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
321        use StoreInstantiationError::*;
322        match self {
323            ActiveDataWriteOutOfBounds => {
324                f.write_str("Active data writing in memory is out of bounds")
325            }
326            I64ValueOutOfReach(s) => f.write_fmt(format_args!(
327                "I64 value {}is out of reach",
328                if !s.is_empty() {
329                    format!("for {s} ")
330                } else {
331                    "".to_string()
332                }
333            )),
334            MissingValueOnTheStack => f.write_str(""),
335            TooManyMemories(x) => f.write_fmt(format_args!("Too many memories (overflow): {x}")),
336        }
337    }
338}
339
340impl Display for LinkerError {
341    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
342        use LinkerError::*;
343        match self {
344            UnmetImport => f.write_str("Unmet import"),
345        }
346    }
347}
348
349pub type Result<T> = core::result::Result<T, Error>;
350
351impl From<RuntimeError> for Error {
352    fn from(value: RuntimeError) -> Self {
353        Self::RuntimeError(value)
354    }
355}
356
357impl From<StoreInstantiationError> for Error {
358    fn from(value: StoreInstantiationError) -> Self {
359        Self::StoreInstantiationError(value)
360    }
361}