casper_wasmi_core/
trap.rs

1use crate::HostError;
2use alloc::boxed::Box;
3use core::fmt::{self, Display};
4
5#[cfg(feature = "std")]
6use std::error::Error as StdError;
7
8/// Error type which can be thrown by wasm code or by host environment.
9///
10/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.
11/// Traps can't be handled by WebAssembly code, but are reported to the embedder.
12#[derive(Debug)]
13pub enum Trap {
14    /// Traps during Wasm execution.
15    Code(TrapCode),
16    /// Traps and errors during host execution.
17    Host(Box<dyn HostError>),
18}
19
20impl Trap {
21    /// Wraps the host error in a [`Trap`].
22    #[inline]
23    pub fn host<U>(host_error: U) -> Self
24    where
25        U: HostError + Sized,
26    {
27        Self::Host(Box::new(host_error))
28    }
29
30    /// Returns `true` if `self` trap originating from host code.
31    #[inline]
32    pub fn is_host(&self) -> bool {
33        matches!(self, Self::Host(_))
34    }
35
36    /// Returns the [`TrapCode`] traps originating from Wasm execution.
37    #[inline]
38    pub fn code(&self) -> Option<TrapCode> {
39        if let Self::Code(trap_code) = self {
40            return Some(*trap_code);
41        }
42        None
43    }
44}
45
46impl From<TrapCode> for Trap {
47    #[inline]
48    fn from(error: TrapCode) -> Self {
49        Self::Code(error)
50    }
51}
52
53impl<U> From<U> for Trap
54where
55    U: HostError + Sized,
56{
57    #[inline]
58    fn from(e: U) -> Self {
59        Trap::host(e)
60    }
61}
62
63impl Display for Trap {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        match self {
66            Trap::Code(trap_code) => Display::fmt(trap_code, f),
67            Trap::Host(host_error) => Display::fmt(host_error, f),
68        }
69    }
70}
71
72#[cfg(feature = "std")]
73impl StdError for Trap {
74    fn description(&self) -> &str {
75        self.code().map(|code| code.trap_message()).unwrap_or("")
76    }
77}
78
79/// Error type which can be thrown by wasm code or by host environment.
80///
81/// See [`Trap`] for details.
82///
83/// [`Trap`]: struct.Trap.html
84#[derive(Debug, Copy, Clone)]
85pub enum TrapCode {
86    /// Wasm code executed `unreachable` opcode.
87    ///
88    /// `unreachable` is a special opcode which always traps upon execution.
89    /// This opcode have a similar purpose as `ud2` in x86.
90    Unreachable,
91
92    /// Attempt to load or store at the address which
93    /// lies outside of bounds of the memory.
94    ///
95    /// Since addresses are interpreted as unsigned integers, out of bounds access
96    /// can't happen with negative addresses (i.e. they will always wrap).
97    MemoryAccessOutOfBounds,
98
99    /// Attempt to access table element at index which
100    /// lies outside of bounds.
101    ///
102    /// This typically can happen when `call_indirect` is executed
103    /// with index that lies out of bounds.
104    ///
105    /// Since indexes are interpreted as unsinged integers, out of bounds access
106    /// can't happen with negative indexes (i.e. they will always wrap).
107    TableAccessOutOfBounds,
108
109    /// Attempt to access table element which is uninitialized (i.e. `None`).
110    ///
111    /// This typically can happen when `call_indirect` is executed.
112    ElemUninitialized,
113
114    /// Attempt to divide by zero.
115    ///
116    /// This trap typically can happen if `div` or `rem` is executed with
117    /// zero as divider.
118    DivisionByZero,
119
120    /// An integer arithmetic operation caused an overflow.
121    ///
122    /// This can happen when:
123    ///
124    /// - Trying to do signed division (or get the remainder) -2<sup>N-1</sup> over -1. This is
125    ///   because the result +2<sup>N-1</sup> isn't representable as a N-bit signed integer.
126    IntegerOverflow,
127
128    /// Attempt to make a conversion to an int failed.
129    ///
130    /// This can happen when:
131    ///
132    /// - Trying to truncate NaNs, infinity, or value for which the result is out of range into an integer.
133    InvalidConversionToInt,
134
135    /// Stack overflow.
136    ///
137    /// This is likely caused by some infinite or very deep recursion.
138    /// Extensive inlining might also be the cause of stack overflow.
139    StackOverflow,
140
141    /// Attempt to invoke a function with mismatching signature.
142    ///
143    /// This can happen if a Wasm or host function was invoked
144    /// with mismatching parameters or result values.
145    ///
146    /// This can always happen with indirect calls as they always
147    /// specify the expected signature of function. If an indirect call is executed
148    /// with an index that points to a function with signature different of what is
149    /// expected by this indirect call, this trap is raised.
150    UnexpectedSignature,
151}
152
153impl TrapCode {
154    /// Returns the trap message as specified by the WebAssembly specification.
155    ///
156    /// # Note
157    ///
158    /// This API is primarily useful for the Wasm spec testsuite but might have
159    /// other uses since it avoid heap memory allocation in certain cases.
160    pub fn trap_message(&self) -> &'static str {
161        match self {
162            TrapCode::Unreachable => "unreachable",
163            TrapCode::MemoryAccessOutOfBounds => "out of bounds memory access",
164            TrapCode::TableAccessOutOfBounds => "undefined element",
165            TrapCode::ElemUninitialized => "uninitialized element",
166            TrapCode::DivisionByZero => "integer divide by zero",
167            TrapCode::IntegerOverflow => "integer overflow",
168            TrapCode::InvalidConversionToInt => "invalid conversion to integer",
169            TrapCode::StackOverflow => "call stack exhausted",
170            TrapCode::UnexpectedSignature => "indirect call type mismatch",
171        }
172    }
173}
174
175impl Display for TrapCode {
176    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177        write!(f, "{}", self.trap_message())
178    }
179}