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_derive::{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 /// An array access attempted to index beyond its array's bounds. 31 ArrayOutOfBounds, 32 33 /// Indirect call to a null table entry. 34 IndirectCallToNull, 35 36 /// Signature mismatch on indirect call. 37 BadSignature, 38 39 /// An integer arithmetic operation caused an overflow. 40 IntegerOverflow, 41 42 /// An integer division by zero. 43 IntegerDivisionByZero, 44 45 /// Failed float-to-int conversion. 46 BadConversionToInteger, 47 48 /// Code that was supposed to have been unreachable was reached. 49 UnreachableCodeReached, 50 51 /// Execution has potentially run too long and may be interrupted. 52 Interrupt, 53 54 /// A user-defined trap code. 55 User(u16), 56 57 /// A null reference was encountered which was required to be non-null. 58 NullReference, 59 60 /// A requested memory allocation was too large: beyond implementation 61 /// limits, would trigger overflows, or etc... 62 AllocationTooLarge, 63 } 64 65 impl TrapCode { 66 /// Returns a slice of all traps except `TrapCode::User` traps 67 pub const fn non_user_traps() -> &'static [TrapCode] { 68 &[ 69 TrapCode::StackOverflow, 70 TrapCode::HeapOutOfBounds, 71 TrapCode::HeapMisaligned, 72 TrapCode::TableOutOfBounds, 73 TrapCode::IndirectCallToNull, 74 TrapCode::BadSignature, 75 TrapCode::IntegerOverflow, 76 TrapCode::IntegerDivisionByZero, 77 TrapCode::BadConversionToInteger, 78 TrapCode::UnreachableCodeReached, 79 TrapCode::Interrupt, 80 TrapCode::NullReference, 81 ] 82 } 83 } 84 85 impl Display for TrapCode { 86 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 87 use self::TrapCode::*; 88 let identifier = match *self { 89 StackOverflow => "stk_ovf", 90 HeapOutOfBounds => "heap_oob", 91 HeapMisaligned => "heap_misaligned", 92 TableOutOfBounds => "table_oob", 93 IndirectCallToNull => "icall_null", 94 BadSignature => "bad_sig", 95 IntegerOverflow => "int_ovf", 96 IntegerDivisionByZero => "int_divz", 97 BadConversionToInteger => "bad_toint", 98 UnreachableCodeReached => "unreachable", 99 Interrupt => "interrupt", 100 User(x) => return write!(f, "user{x}"), 101 NullReference => "null_reference", 102 ArrayOutOfBounds => "array_oob", 103 AllocationTooLarge => "alloc_too_large", 104 }; 105 f.write_str(identifier) 106 } 107 } 108 109 impl FromStr for TrapCode { 110 type Err = (); 111 112 fn from_str(s: &str) -> Result<Self, Self::Err> { 113 use self::TrapCode::*; 114 match s { 115 "stk_ovf" => Ok(StackOverflow), 116 "heap_oob" => Ok(HeapOutOfBounds), 117 "heap_misaligned" => Ok(HeapMisaligned), 118 "table_oob" => Ok(TableOutOfBounds), 119 "icall_null" => Ok(IndirectCallToNull), 120 "bad_sig" => Ok(BadSignature), 121 "int_ovf" => Ok(IntegerOverflow), 122 "int_divz" => Ok(IntegerDivisionByZero), 123 "bad_toint" => Ok(BadConversionToInteger), 124 "unreachable" => Ok(UnreachableCodeReached), 125 "interrupt" => Ok(Interrupt), 126 "null_reference" => Ok(NullReference), 127 "array_oob" => Ok(ArrayOutOfBounds), 128 "alloc_too_large" => Ok(AllocationTooLarge), 129 _ if s.starts_with("user") => s[4..].parse().map(User).map_err(|_| ()), 130 _ => Err(()), 131 } 132 } 133 } 134 135 #[cfg(test)] 136 mod tests { 137 use super::*; 138 use alloc::string::ToString; 139 140 #[test] 141 fn display() { 142 for r in TrapCode::non_user_traps() { 143 let tc = *r; 144 assert_eq!(tc.to_string().parse(), Ok(tc)); 145 } 146 assert_eq!("bogus".parse::<TrapCode>(), Err(())); 147 148 assert_eq!(TrapCode::User(17).to_string(), "user17"); 149 assert_eq!("user22".parse(), Ok(TrapCode::User(22))); 150 assert_eq!("user".parse::<TrapCode>(), Err(())); 151 assert_eq!("user-1".parse::<TrapCode>(), Err(())); 152 assert_eq!("users".parse::<TrapCode>(), Err(())); 153 } 154 } 155