Coverage Report

Created: 2025-06-23 13:53

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
}
35
36
#[derive(Debug, PartialEq, Eq, Clone)]
37
pub enum Proposal {
38
    Memory64,
39
    MultipleMemories,
40
    Threads,
41
}
42
43
#[derive(Debug, PartialEq, Eq, Clone)]
44
pub enum StoreInstantiationError {
45
    ActiveDataWriteOutOfBounds,
46
    I64ValueOutOfReach(String),
47
    MissingValueOnTheStack,
48
    TooManyMemories(usize),
49
}
50
51
#[derive(Debug, PartialEq, Eq, Clone)]
52
pub enum LinkerError {
53
    UnmetImport,
54
}
55
56
#[derive(Debug, PartialEq, Eq, Clone)]
57
pub 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
124
impl Display for Error {
125
0
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
126
0
        match self {
127
            Error::InvalidMagic => {
128
0
                f.write_str("The magic number at the very start of the given WASM file is invalid.")
129
            }
130
0
            Error::InvalidVersion => f.write_str("The version in the WASM file header is invalid"),
131
0
            Error::MalformedUtf8String(err) => f.write_fmt(format_args!(
132
0
                "A name could not be parsed as it was invalid UTF8: {err}"
133
0
            )),
134
0
            Error::Eof => f.write_str(
135
0
                "A value was expected in the WASM binary but the end of file was reached instead",
136
0
            ),
137
0
            Error::InvalidSection(section, reason) => f.write_fmt(format_args!(
138
0
                "Section '{:?}' invalid! Reason: {}",
139
0
                section, 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[{}] is NOT defined when it should be",
207
0
                memidx
208
0
            )),
209
0
            Error::ErroneousAlignment(mem_align, minimum_wanted_alignment) => {
210
0
                f.write_fmt(format_args!(
211
0
                    "Alignment ({}) is not less or equal to {}",
212
0
                    mem_align, minimum_wanted_alignment
213
0
                ))
214
            }
215
0
            Error::NoDataSegments => f.write_str("Data Count is None"),
216
0
            Error::DataSegmentNotFound(data_idx) => {
217
0
                f.write_fmt(format_args!("Data Segment {} not found", data_idx))
218
            }
219
0
            Error::InvalidLabelIdx(label_idx) => {
220
0
                f.write_fmt(format_args!("invalid label index {}", label_idx))
221
            }
222
            Error::ValidationCtrlStackEmpty => {
223
0
                f.write_str("cannot retrieve last ctrl block, validation ctrl stack is empty")
224
            }
225
            Error::ElseWithoutMatchingIf => {
226
0
                f.write_str("read 'else' without a previous matching 'if' instruction")
227
            }
228
            Error::IfWithoutMatchingElse => {
229
0
                f.write_str("read 'end' without matching 'else' instruction to 'if' instruction")
230
            }
231
0
            Error::TableIsNotDefined(table_idx) => f.write_fmt(format_args!(
232
0
                "C.tables[{}] is NOT defined when it should be",
233
0
                table_idx
234
0
            )),
235
0
            Error::ElementIsNotDefined(elem_idx) => f.write_fmt(format_args!(
236
0
                "C.elems[{}] is NOT defined when it should be",
237
0
                elem_idx
238
0
            )),
239
0
            Error::DifferentRefTypes(rref1, rref2) => f.write_fmt(format_args!(
240
0
                "RefType {:?} is NOT equal to RefType {:?}",
241
0
                rref1, rref2
242
0
            )),
243
0
            Error::ExpectedARefType(found_valtype) => f.write_fmt(format_args!(
244
0
                "Expected a RefType, found a {:?} instead",
245
0
                found_valtype
246
0
            )),
247
0
            Error::WrongRefTypeForInteropValue(ref_given, ref_wanted) => f.write_fmt(format_args!(
248
0
                "Wrong RefType for InteropValue: Given {:?} - Needed {:?}",
249
0
                ref_given, ref_wanted
250
0
            )),
251
0
            Error::FunctionIsNotDefined(func_idx) => f.write_fmt(format_args!(
252
0
                "C.functions[{}] is NOT defined when it should be",
253
0
                func_idx
254
0
            )),
255
0
            Error::ReferencingAnUnreferencedFunction(func_idx) => f.write_fmt(format_args!(
256
0
                "Referenced a function ({}) that was not referenced in validation",
257
0
                func_idx
258
0
            )),
259
0
            Error::FunctionTypeIsNotDefined(func_ty_idx) => f.write_fmt(format_args!(
260
0
                "C.fn_types[{}] is NOT defined when it should be",
261
0
                func_ty_idx
262
0
            )),
263
0
            Error::StoreInstantiationError(err) => err.fmt(f),
264
0
            Error::OnlyFuncRefIsAllowed => f.write_str("Only FuncRef is allowed"),
265
            Error::TypeUnificationMismatch => {
266
0
                f.write_str("cannot unify types")
267
            }
268
            Error::InvalidSelectTypeVector => {
269
0
                f.write_str("SELECT T* (0x1C) instruction must have exactly one type in the subsequent type vector")
270
            }
271
0
            Error::TooManyLocals(x) => {
272
0
                f.write_fmt(format_args!("Too many locals (more than 2^32-1): {}", x))
273
            }
274
0
            Error::UnsupportedProposal(proposal) => {
275
0
                f.write_fmt(format_args!("Unsupported proposal: {:?}", proposal))
276
            }
277
0
            Error::Overflow => f.write_str("Overflow"),
278
0
            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
0
            Error::UnknownFunction => f.write_str("Unknown function"),
282
0
            Error::UnknownMemory => f.write_str("Unknown memory"),
283
0
            Error::UnknownGlobal => f.write_str("Unknown global"),
284
0
            Error::UnknownTable => f.write_str("Unknown table"),
285
0
            Error::DuplicateExportName => f.write_str("Duplicate export name"),
286
0
            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
0
            Error::UnknownImport => f.write_str("Unknown Import"),
289
290
        }
291
0
    }
292
}
293
294
impl Display for RuntimeError {
295
1
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
296
1
        match self {
297
0
            RuntimeError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
298
0
            RuntimeError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
299
0
            RuntimeError::FunctionNotFound => f.write_str("Function not found"),
300
1
            RuntimeError::BadConversionToInteger => f.write_str("Bad conversion to integer"),
301
0
            RuntimeError::MemoryAccessOutOfBounds => f.write_str("Memory access out of bounds"),
302
0
            RuntimeError::TableAccessOutOfBounds => f.write_str("Table access out of bounds"),
303
0
            RuntimeError::ElementAccessOutOfBounds => f.write_str("Element access out of bounds"),
304
0
            RuntimeError::UninitializedElement => f.write_str("Uninitialized element"),
305
0
            RuntimeError::SignatureMismatch => f.write_str("Indirect call signature mismatch"),
306
            RuntimeError::ExpectedAValueOnTheStack => {
307
0
                f.write_str("Expected a value on the stack, but None was found")
308
            }
309
0
            RuntimeError::ModuleNotFound => f.write_str("No such module exists"),
310
            RuntimeError::UnmetImport => {
311
0
                f.write_str("There is at least one import which has no corresponding export")
312
            }
313
            RuntimeError::UndefinedTableIndex => {
314
0
                f.write_str("Indirect call: table index out of bounds")
315
            }
316
            RuntimeError::ReachedUnreachable => {
317
0
                f.write_str("an unreachable statement was reached, triggered a trap")
318
            }
319
            RuntimeError::StackExhaustion => {
320
0
                f.write_str("either the call stack or the value stack overflowed")
321
            }
322
        }
323
1
    }
324
}
325
326
impl Display for StoreInstantiationError {
327
0
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
328
        use StoreInstantiationError::*;
329
0
        match self {
330
            ActiveDataWriteOutOfBounds => {
331
0
                f.write_str("Active data writing in memory is out of bounds")
332
            }
333
0
            I64ValueOutOfReach(s) => f.write_fmt(format_args!(
334
0
                "I64 value {}is out of reach",
335
0
                if !s.is_empty() {
336
0
                    format!("for {s} ")
337
                } else {
338
0
                    "".to_string()
339
                }
340
            )),
341
0
            MissingValueOnTheStack => f.write_str(""),
342
0
            TooManyMemories(x) => f.write_fmt(format_args!("Too many memories (overflow): {}", x)),
343
        }
344
0
    }
345
}
346
347
impl Display for LinkerError {
348
0
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
349
        use LinkerError::*;
350
0
        match self {
351
0
            UnmetImport => f.write_str("Unmet import"),
352
0
        }
353
0
    }
354
}
355
356
pub type Result<T> = core::result::Result<T, Error>;
357
358
impl From<RuntimeError> for Error {
359
0
    fn from(value: RuntimeError) -> Self {
360
0
        Self::RuntimeError(value)
361
0
    }
362
}
363
364
impl From<StoreInstantiationError> for Error {
365
0
    fn from(value: StoreInstantiationError) -> Self {
366
0
        Self::StoreInstantiationError(value)
367
0
    }
368
}