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}