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