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