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