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