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}