near_vm_vm/trap/
trapcode.rs1use core::fmt::{self, Display, Formatter};
7use core::str::FromStr;
8use thiserror::Error;
9
10#[derive(
14 Clone,
15 Copy,
16 PartialEq,
17 Eq,
18 Debug,
19 Hash,
20 Error,
21 rkyv::Serialize,
22 rkyv::Deserialize,
23 rkyv::Archive,
24)]
25#[repr(u32)]
26pub enum TrapCode {
27 StackOverflow = 0,
32
33 HeapAccessOutOfBounds = 1,
39
40 HeapMisaligned = 2,
42
43 TableAccessOutOfBounds = 3,
45
46 OutOfBounds = 4,
48
49 IndirectCallToNull = 5,
51
52 BadSignature = 6,
54
55 IntegerOverflow = 7,
57
58 IntegerDivisionByZero = 8,
60
61 BadConversionToInteger = 9,
63
64 UnreachableCodeReached = 10,
66
67 UnalignedAtomic = 11,
69
70 GasExceeded = 12,
72}
73
74impl TrapCode {
75 pub fn message(&self) -> &str {
77 match self {
78 Self::StackOverflow => "call stack exhausted",
79 Self::HeapAccessOutOfBounds => "out of bounds memory access",
80 Self::HeapMisaligned => "misaligned heap",
81 Self::TableAccessOutOfBounds => "undefined element: out of bounds table access",
82 Self::OutOfBounds => "out of bounds",
83 Self::IndirectCallToNull => "uninitialized element",
84 Self::BadSignature => "indirect call type mismatch",
85 Self::IntegerOverflow => "integer overflow",
86 Self::IntegerDivisionByZero => "integer divide by zero",
87 Self::BadConversionToInteger => "invalid conversion to integer",
88 Self::UnreachableCodeReached => "unreachable",
89 Self::UnalignedAtomic => "unaligned atomic access",
90 Self::GasExceeded => "gas limit exceeded",
91 }
92 }
93}
94
95impl Display for TrapCode {
96 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
97 let identifier = match *self {
98 Self::StackOverflow => "stk_ovf",
99 Self::HeapAccessOutOfBounds => "heap_get_oob",
100 Self::HeapMisaligned => "heap_misaligned",
101 Self::TableAccessOutOfBounds => "table_get_oob",
102 Self::OutOfBounds => "oob",
103 Self::IndirectCallToNull => "icall_null",
104 Self::BadSignature => "bad_sig",
105 Self::IntegerOverflow => "int_ovf",
106 Self::IntegerDivisionByZero => "int_divz",
107 Self::BadConversionToInteger => "bad_toint",
108 Self::UnreachableCodeReached => "unreachable",
109 Self::UnalignedAtomic => "unalign_atom",
110 Self::GasExceeded => "out_of_gas",
111 };
112 f.write_str(identifier)
113 }
114}
115
116impl FromStr for TrapCode {
117 type Err = ();
118
119 fn from_str(s: &str) -> Result<Self, Self::Err> {
120 match s {
121 "stk_ovf" => Ok(Self::StackOverflow),
122 "heap_get_oob" => Ok(Self::HeapAccessOutOfBounds),
123 "heap_misaligned" => Ok(Self::HeapMisaligned),
124 "table_get_oob" => Ok(Self::TableAccessOutOfBounds),
125 "oob" => Ok(Self::OutOfBounds),
126 "icall_null" => Ok(Self::IndirectCallToNull),
127 "bad_sig" => Ok(Self::BadSignature),
128 "int_ovf" => Ok(Self::IntegerOverflow),
129 "int_divz" => Ok(Self::IntegerDivisionByZero),
130 "bad_toint" => Ok(Self::BadConversionToInteger),
131 "unreachable" => Ok(Self::UnreachableCodeReached),
132 "unalign_atom" => Ok(Self::UnalignedAtomic),
133 _ => Err(()),
134 }
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 const CODES: [TrapCode; 12] = [
144 TrapCode::StackOverflow,
145 TrapCode::HeapAccessOutOfBounds,
146 TrapCode::HeapMisaligned,
147 TrapCode::TableAccessOutOfBounds,
148 TrapCode::OutOfBounds,
149 TrapCode::IndirectCallToNull,
150 TrapCode::BadSignature,
151 TrapCode::IntegerOverflow,
152 TrapCode::IntegerDivisionByZero,
153 TrapCode::BadConversionToInteger,
154 TrapCode::UnreachableCodeReached,
155 TrapCode::UnalignedAtomic,
156 ];
157
158 #[test]
159 fn display() {
160 for r in &CODES {
161 let tc = *r;
162 assert_eq!(tc.to_string().parse(), Ok(tc));
163 }
164 assert_eq!("bogus".parse::<TrapCode>(), Err(()));
165
166 assert_eq!("user".parse::<TrapCode>(), Err(()));
169 assert_eq!("user-1".parse::<TrapCode>(), Err(()));
170 assert_eq!("users".parse::<TrapCode>(), Err(()));
171 }
172}