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    /// The identifier of a stored object did not match the
22    /// [`Store`](crate::execution::store::Store) it was used with.
23    StoreIdMismatch,
24
25    // Are all of these instantiation variants? Add a new `InstantiationError` enum?
26    InvalidImportType,
27    UnknownImport,
28    /// It was attempted to register a symbol under a name for which a symbol already exists.
29    RegistrySymbolAlreadyExists,
30    MoreThanOneMemory,
31    /// Fueled execution that is not resumable has ran out of fuel.
32    OutOfFuel,
33    /// The number of module exports did not match the number of extern values
34    /// provided for instantiation.
35    ExternValsLenMismatch,
36    /// Happens when a definition would cause an extern to be defined with a
37    /// module name and name for which an extern already exists.
38    DuplicateExternDefinition,
39
40    /// An extern lookup could not be resolved because no matching extern value existed for it.
41    UnableToResolveExternLookup,
42
43    /// A function was invoked with incorrect parameters or return types.
44    FunctionInvocationSignatureMismatch,
45
46    /// A checked method of a [`Linker`](crate::execution::linker::Linker) was
47    /// used, even though that [`Linker`](crate::execution::linker::Linker) has
48    /// not yet been associated to any store through its id.
49    LinkerNotYetAssociatedWithStoreId,
50}
51
52impl Display for RuntimeError {
53    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
54        match self {
55            RuntimeError::Trap(trap_error) => write!(f, "{trap_error}"),
56            RuntimeError::FunctionNotFound => f.write_str("Function not found"),
57            RuntimeError::ModuleNotFound => f.write_str("No such module exists"),
58            RuntimeError::ResumableNotFound => f.write_str("No such resumable exists"),
59            RuntimeError::StackExhaustion => {
60                f.write_str("either the call stack or the value stack overflowed")
61            }
62            RuntimeError::HostFunctionSignatureMismatch => {
63                f.write_str("host function call did not respect its type signature")
64            }
65            RuntimeError::HostFunctionHaltedExecution => {
66                f.write_str("A host function requested execution to be halted.")
67            }
68            RuntimeError::InvalidImportType => f.write_str("Invalid import type"),
69            RuntimeError::TableAccessOutOfBounds => f.write_str("A table access was out of bounds"),
70            RuntimeError::RegistrySymbolAlreadyExists => f.write_str(
71                "It was attempted to register a symbol under a name for which a symbol already exists.",
72            ),
73            RuntimeError::UnknownExport => {
74                f.write_str("An unknown export was referenced by its name.")
75            }
76            RuntimeError::TableTypeMismatch => {
77                f.write_str("An alloc/write operation failed on a table due to a type mismatch.")
78            }
79            // TODO: maybe move these to LinkerError also add more info to them (the name's export, function idx, etc)
80            RuntimeError::UnknownImport => f.write_str("Unknown Import"),
81            RuntimeError::MoreThanOneMemory => {
82                f.write_str("As of not only one memory is allowed per module.")
83            }
84
85            RuntimeError::WriteOnImmutableGlobal => f.write_str(
86                "A write operation on a global failed due to the global being immutable",
87            ),
88            RuntimeError::GlobalTypeMismatch => {
89                f.write_str("An alloc/write operation on a global failed due to a type mismatch")
90            }
91            RuntimeError::OutOfFuel => {
92                f.write_str("Fueled execution that is not resumable has ran out of fuel")
93            }
94            RuntimeError::ExternValsLenMismatch => {
95                f.write_str("The number of module exports did not match the number of extern values provided for instantiation.")
96            }
97            RuntimeError::DuplicateExternDefinition => {
98                f.write_str("Linking failed because of a duplicate definition of some extern value")
99            }
100            RuntimeError::UnableToResolveExternLookup => {
101                f.write_str("An extern lookup could not be resolved because no matching extern value existed for it.")
102            }
103            RuntimeError::FunctionInvocationSignatureMismatch => {
104                f.write_str("A function was invoked with incorrect parameters or return types")
105            }
106            RuntimeError::StoreIdMismatch => f.write_str( "The identifier of a stored object did not match the store it was used with"),
107            RuntimeError::LinkerNotYetAssociatedWithStoreId => f.write_str("A checked method of a linker was used, even though that linker has not yet been associated to any store through its id"),
108        }
109    }
110}
111
112#[derive(Debug, PartialEq, Eq, Clone)]
113pub enum TrapError {
114    DivideBy0,
115    UnrepresentableResult,
116    // https://github.com/wasmi-labs/wasmi/blob/37d1449524a322817c55026eb21eb97dd693b9ce/crates/core/src/trap.rs#L265C5-L265C27
117    BadConversionToInteger,
118
119    /// An access to a memory or data was out of bounds.
120    ///
121    /// Note: As of now, there is no way to distinguish between both of these. The reference
122    /// interpreter and Wast testsuite messages call this error "memory access out of bounds".
123    MemoryOrDataAccessOutOfBounds,
124    /// An access to a table or an element was out of bounds.
125    ///
126    /// Note: As of now, there is no way to distinguish between both of these. The reference
127    /// interpreter and Wast testsuite messages call this error "table access out of bounds".
128    TableOrElementAccessOutOfBounds,
129    UninitializedElement,
130    SignatureMismatch,
131    IndirectCallNullFuncRef,
132    TableAccessOutOfBounds,
133    ReachedUnreachable,
134}
135
136impl Display for TrapError {
137    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
138        match self {
139            TrapError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
140            TrapError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
141            TrapError::BadConversionToInteger => f.write_str("Bad conversion to integer"),
142            TrapError::MemoryOrDataAccessOutOfBounds => {
143                f.write_str("Memory or data access out of bounds")
144            }
145            TrapError::TableOrElementAccessOutOfBounds => {
146                f.write_str("Table or element access out of bounds")
147            }
148            TrapError::UninitializedElement => f.write_str("Uninitialized element"),
149            TrapError::SignatureMismatch => f.write_str("Indirect call signature mismatch"),
150            TrapError::IndirectCallNullFuncRef => {
151                f.write_str("Indirect call targeted null reference")
152            }
153            TrapError::TableAccessOutOfBounds => {
154                f.write_str("Indirect call: table index out of bounds")
155            }
156            TrapError::ReachedUnreachable => {
157                f.write_str("an unreachable statement was reached, triggered a trap")
158            }
159        }
160    }
161}
162
163impl From<TrapError> for RuntimeError {
164    fn from(value: TrapError) -> Self {
165        Self::Trap(value)
166    }
167}