Coverage Report

Created: 2025-08-05 11:48

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