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