wasmer_vm/trap/
trap.rs

1use backtrace::Backtrace;
2use std::error::Error;
3use std::fmt;
4use wasmer_types::TrapCode;
5
6use crate::{StoreObjects, VMExceptionRef};
7
8/// Stores trace message with backtrace.
9#[derive(Debug)]
10pub enum Trap {
11    /// A user-raised trap through `raise_user_trap`.
12    User(Box<dyn Error + Send + Sync>),
13
14    /// A trap raised from the Wasm generated code
15    ///
16    /// Note: this trap is deterministic (assuming a deterministic host implementation)
17    Wasm {
18        /// The program counter in generated code where this trap happened.
19        pc: usize,
20        /// Native stack backtrace at the time the trap occurred
21        backtrace: Backtrace,
22        /// Optional trapcode associated to the signal that caused the trap
23        signal_trap: Option<TrapCode>,
24    },
25
26    /// A trap raised from a wasm libcall
27    ///
28    /// Note: this trap is deterministic (assuming a deterministic host implementation)
29    Lib {
30        /// Code of the trap.
31        trap_code: TrapCode,
32        /// Native stack backtrace at the time the trap occurred
33        backtrace: Backtrace,
34    },
35
36    /// A trap indicating that the runtime was unable to allocate sufficient memory.
37    ///
38    /// Note: this trap is nondeterministic, since it depends on the host system.
39    OOM {
40        /// Native stack backtrace at the time the OOM occurred
41        backtrace: Backtrace,
42    },
43
44    /// A WASM exception was thrown but not caught.
45    UncaughtException {
46        /// The exception reference of the uncaught exception.
47        exnref: VMExceptionRef,
48        /// Native stack backtrace at the time the exception was thrown.
49        /// This is a clone of the backtrace stored in the exception itself.
50        backtrace: Backtrace,
51    },
52}
53
54fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
55    (t, t)
56}
57
58impl Trap {
59    /// Construct a new Error with the given a user error.
60    ///
61    /// Internally saves a backtrace when constructed.
62    pub fn user(err: Box<dyn Error + Send + Sync>) -> Self {
63        Self::User(err)
64    }
65
66    /// Construct a new Wasm trap with the given source location and backtrace.
67    ///
68    /// Internally saves a backtrace when constructed.
69    pub fn wasm(pc: usize, backtrace: Backtrace, signal_trap: Option<TrapCode>) -> Self {
70        Self::Wasm {
71            pc,
72            backtrace,
73            signal_trap,
74        }
75    }
76
77    /// Returns trap code, if it's a Trap
78    pub fn to_trap(self) -> Option<TrapCode> {
79        unimplemented!()
80    }
81
82    /// Construct a new Wasm trap with the given trap code.
83    ///
84    /// Internally saves a backtrace when constructed.
85    pub fn lib(trap_code: TrapCode) -> Self {
86        let backtrace = Backtrace::new_unresolved();
87        Self::Lib {
88            trap_code,
89            backtrace,
90        }
91    }
92
93    /// Construct a new OOM trap with the given source location and trap code.
94    ///
95    /// Internally saves a backtrace when constructed.
96    pub fn oom() -> Self {
97        let backtrace = Backtrace::new_unresolved();
98        Self::OOM { backtrace }
99    }
100
101    /// Construct a new UncaughtException trap with the given exception reference.
102    pub fn uncaught_exception(exnref: VMExceptionRef, ctx: &StoreObjects) -> Self {
103        Self::UncaughtException {
104            backtrace: exnref.0.get(ctx).backtrace().clone(),
105            exnref,
106        }
107    }
108
109    /// Attempts to downcast the `Trap` to a concrete type.
110    pub fn downcast<T: Error + 'static>(self) -> Result<T, Self> {
111        match self {
112            // We only try to downcast user errors
113            Self::User(err) if err.is::<T>() => Ok(*err.downcast::<T>().unwrap()),
114            _ => Err(self),
115        }
116    }
117
118    /// Attempts to downcast the `Trap` to a concrete type.
119    pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
120        match &self {
121            // We only try to downcast user errors
122            Self::User(err) if err.is::<T>() => err.downcast_ref::<T>(),
123            _ => None,
124        }
125    }
126
127    /// Returns true if the `Trap` is the same as T
128    pub fn is<T: Error + 'static>(&self) -> bool {
129        match self {
130            Self::User(err) => err.is::<T>(),
131            _ => false,
132        }
133    }
134
135    /// Returns true if the trap is an exception
136    pub fn is_exception(&self) -> bool {
137        matches!(self, Self::UncaughtException { .. })
138    }
139
140    /// If the `Trap` is an uncaught exception, returns it.
141    pub fn to_exception_ref(&self) -> Option<VMExceptionRef> {
142        match self {
143            // Self::UncaughtException { exnref, .. } => Some(Exception::from_vm_exceptionref(
144            //     crate::vm::VMExceptionRef::Sys(exnref.clone()),
145            // )),
146            Self::UncaughtException { exnref, .. } => Some(exnref.clone()),
147            _ => None,
148        }
149    }
150}
151
152impl std::error::Error for Trap {
153    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
154        match &self {
155            Self::User(err) => Some(&**err),
156            _ => None,
157        }
158    }
159}
160
161impl fmt::Display for Trap {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        match self {
164            Self::User(e) => write!(f, "{e}"),
165            Self::Lib { .. } => write!(f, "lib"),
166            Self::Wasm { .. } => write!(f, "wasm"),
167            Self::OOM { .. } => write!(f, "Wasmer VM out of memory"),
168            Self::UncaughtException { .. } => write!(f, "Uncaught wasm exception"),
169        }
170    }
171}