1 //! Trap codes describing the reason for a trap. 2 3 use core::fmt::{self, Display, Formatter}; 4 use core::str::FromStr; 5 #[cfg(feature = "enable-serde")] 6 use serde::{Deserialize, Serialize}; 7 8 /// A trap code describing the reason for a trap. 9 /// 10 /// All trap instructions have an explicit trap code. 11 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 12 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 13 pub enum TrapCode { 14 /// The current stack space was exhausted. 15 StackOverflow, 16 17 /// A `heap_addr` instruction detected an out-of-bounds error. 18 /// 19 /// Note that not all out-of-bounds heap accesses are reported this way; 20 /// some are detected by a segmentation fault on the heap unmapped or 21 /// offset-guard pages. 22 HeapOutOfBounds, 23 24 /// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address. 25 HeapMisaligned, 26 27 /// A `table_addr` instruction detected an out-of-bounds error. 28 TableOutOfBounds, 29 30 /// Indirect call to a null table entry. 31 IndirectCallToNull, 32 33 /// Signature mismatch on indirect call. 34 BadSignature, 35 36 /// An integer arithmetic operation caused an overflow. 37 IntegerOverflow, 38 39 /// An integer division by zero. 40 IntegerDivisionByZero, 41 42 /// Failed float-to-int conversion. 43 BadConversionToInteger, 44 45 /// Code that was supposed to have been unreachable was reached. 46 UnreachableCodeReached, 47 48 /// Execution has potentially run too long and may be interrupted. 49 /// This trap is resumable. 50 Interrupt, 51 52 /// A user-defined trap code. 53 User(u16), 54 } 55 56 impl TrapCode { 57 /// Returns a slice of all traps except `TrapCode::User` traps 58 pub const fn non_user_traps() -> &'static [TrapCode] { 59 &[ 60 TrapCode::StackOverflow, 61 TrapCode::HeapOutOfBounds, 62 TrapCode::HeapMisaligned, 63 TrapCode::TableOutOfBounds, 64 TrapCode::IndirectCallToNull, 65 TrapCode::BadSignature, 66 TrapCode::IntegerOverflow, 67 TrapCode::IntegerDivisionByZero, 68 TrapCode::BadConversionToInteger, 69 TrapCode::UnreachableCodeReached, 70 TrapCode::Interrupt, 71 ] 72 } 73 } 74 75 impl Display for TrapCode { 76 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 77 use self::TrapCode::*; 78 let identifier = match *self { 79 StackOverflow => "stk_ovf", 80 HeapOutOfBounds => "heap_oob", 81 HeapMisaligned => "heap_misaligned", 82 TableOutOfBounds => "table_oob", 83 IndirectCallToNull => "icall_null", 84 BadSignature => "bad_sig", 85 IntegerOverflow => "int_ovf", 86 IntegerDivisionByZero => "int_divz", 87 BadConversionToInteger => "bad_toint", 88 UnreachableCodeReached => "unreachable", 89 Interrupt => "interrupt", 90 User(x) => return write!(f, "user{}", x), 91 }; 92 f.write_str(identifier) 93 } 94 } 95 96 impl FromStr for TrapCode { 97 type Err = (); 98 99 fn from_str(s: &str) -> Result<Self, Self::Err> { 100 use self::TrapCode::*; 101 match s { 102 "stk_ovf" => Ok(StackOverflow), 103 "heap_oob" => Ok(HeapOutOfBounds), 104 "heap_misaligned" => Ok(HeapMisaligned), 105 "table_oob" => Ok(TableOutOfBounds), 106 "icall_null" => Ok(IndirectCallToNull), 107 "bad_sig" => Ok(BadSignature), 108 "int_ovf" => Ok(IntegerOverflow), 109 "int_divz" => Ok(IntegerDivisionByZero), 110 "bad_toint" => Ok(BadConversionToInteger), 111 "unreachable" => Ok(UnreachableCodeReached), 112 "interrupt" => Ok(Interrupt), 113 _ if s.starts_with("user") => s[4..].parse().map(User).map_err(|_| ()), 114 _ => Err(()), 115 } 116 } 117 } 118 119 #[cfg(test)] 120 mod tests { 121 use super::*; 122 use alloc::string::ToString; 123 124 #[test] 125 fn display() { 126 for r in TrapCode::non_user_traps() { 127 let tc = *r; 128 assert_eq!(tc.to_string().parse(), Ok(tc)); 129 } 130 assert_eq!("bogus".parse::<TrapCode>(), Err(())); 131 132 assert_eq!(TrapCode::User(17).to_string(), "user17"); 133 assert_eq!("user22".parse(), Ok(TrapCode::User(22))); 134 assert_eq!("user".parse::<TrapCode>(), Err(())); 135 assert_eq!("user-1".parse::<TrapCode>(), Err(())); 136 assert_eq!("users".parse::<TrapCode>(), Err(())); 137 } 138 } 139