Coverage Report

Created: 2025-01-23 14:27

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