wasm/execution/
error.rs

1use core::fmt::{Display, Formatter};
2
3#[derive(Debug, PartialEq, Eq, Clone)]
4pub enum RuntimeError {
5    Trap(TrapError),
6
7    ModuleNotFound,
8    FunctionNotFound,
9    ResumableNotFound,
10    StackExhaustion,
11    HostFunctionSignatureMismatch,
12    WriteOnImmutableGlobal,
13    GlobalTypeMismatch,
14    /// A host function returned the [`HaltExecutionError`](crate::HaltExecutionError), which caused execution to be halted.
15    HostFunctionHaltedExecution,
16    // An access to a table element was out of bounds
17    TableAccessOutOfBounds,
18    UnknownExport,
19    TableTypeMismatch,
20
21    // Are all of these instantiation variants? Add a new `InstantiationError` enum?
22    InvalidImportType,
23    UnknownImport,
24    /// It was attempted to register a symbol under a name for which a symbol already exists.
25    RegistrySymbolAlreadyExists,
26    MoreThanOneMemory,
27}
28
29impl Display for RuntimeError {
30    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
31        match self {
32            RuntimeError::Trap(trap_error) => write!(f, "{trap_error}"),
33            RuntimeError::FunctionNotFound => f.write_str("Function not found"),
34            RuntimeError::ModuleNotFound => f.write_str("No such module exists"),
35            RuntimeError::ResumableNotFound => f.write_str("No such resumable exists"),
36            RuntimeError::StackExhaustion => {
37                f.write_str("either the call stack or the value stack overflowed")
38            }
39            RuntimeError::HostFunctionSignatureMismatch => {
40                f.write_str("host function call did not respect its type signature")
41            }
42            RuntimeError::HostFunctionHaltedExecution => {
43                f.write_str("A host function requested execution to be halted.")
44            }
45            RuntimeError::InvalidImportType => f.write_str("Invalid import type"),
46            RuntimeError::TableAccessOutOfBounds => f.write_str("A table access was out of bounds"),
47            RuntimeError::RegistrySymbolAlreadyExists => f.write_str(
48                "It was attempted to register a symbol under a name for which a symbol already exists.",
49            ),
50            RuntimeError::UnknownExport => {
51                f.write_str("An unknown export was referenced by its name.")
52            }
53            RuntimeError::TableTypeMismatch => {
54                f.write_str("An alloc/write operation failed on a table due to a type mismatch.")
55            }
56            // TODO: maybe move these to LinkerError also add more info to them (the name's export, function idx, etc)
57            RuntimeError::UnknownImport => f.write_str("Unknown Import"),
58            RuntimeError::MoreThanOneMemory => {
59                f.write_str("As of not only one memory is allowed per module.")
60            }
61
62            RuntimeError::WriteOnImmutableGlobal => f.write_str(
63                "A write operation on a global failed due to the global being immutable",
64            ),
65            RuntimeError::GlobalTypeMismatch => {
66                f.write_str("An alloc/write operation on a global failed due to a type mismatch")
67            }
68        }
69    }
70}
71
72#[derive(Debug, PartialEq, Eq, Clone)]
73pub enum TrapError {
74    DivideBy0,
75    UnrepresentableResult,
76    // https://github.com/wasmi-labs/wasmi/blob/37d1449524a322817c55026eb21eb97dd693b9ce/crates/core/src/trap.rs#L265C5-L265C27
77    BadConversionToInteger,
78
79    /// An access to a memory or data was out of bounds.
80    ///
81    /// Note: As of now, there is no way to distinguish between both of these. The reference
82    /// interpreter and Wast testsuite messages call this error "memory access out of bounds".
83    MemoryOrDataAccessOutOfBounds,
84    /// An access to a table or an element was out of bounds.
85    ///
86    /// Note: As of now, there is no way to distinguish between both of these. The reference
87    /// interpreter and Wast testsuite messages call this error "table access out of bounds".
88    TableOrElementAccessOutOfBounds,
89    UninitializedElement,
90    SignatureMismatch,
91    IndirectCallNullFuncRef,
92    TableAccessOutOfBounds,
93    ReachedUnreachable,
94}
95
96impl Display for TrapError {
97    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
98        match self {
99            TrapError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
100            TrapError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
101            TrapError::BadConversionToInteger => f.write_str("Bad conversion to integer"),
102            TrapError::MemoryOrDataAccessOutOfBounds => {
103                f.write_str("Memory or data access out of bounds")
104            }
105            TrapError::TableOrElementAccessOutOfBounds => {
106                f.write_str("Table or element access out of bounds")
107            }
108            TrapError::UninitializedElement => f.write_str("Uninitialized element"),
109            TrapError::SignatureMismatch => f.write_str("Indirect call signature mismatch"),
110            TrapError::IndirectCallNullFuncRef => {
111                f.write_str("Indirect call targeted null reference")
112            }
113            TrapError::TableAccessOutOfBounds => {
114                f.write_str("Indirect call: table index out of bounds")
115            }
116            TrapError::ReachedUnreachable => {
117                f.write_str("an unreachable statement was reached, triggered a trap")
118            }
119        }
120    }
121}
122
123impl From<TrapError> for RuntimeError {
124    fn from(value: TrapError) -> Self {
125        Self::Trap(value)
126    }
127}