Coverage Report

Created: 2025-02-18 14:57

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