cranelift_codegen/ir/
trapcode.rs

1//! Trap codes describing the reason for a trap.
2
3use core::fmt::{self, Display, Formatter};
4use core::str::FromStr;
5#[cfg(feature = "enable-serde")]
6use 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))]
13pub 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    Interrupt,
50
51    /// A user-defined trap code.
52    User(u16),
53
54    /// A null reference was encountered which was required to be non-null.
55    NullReference,
56
57    /// A null `i31ref` was encountered which was required to be non-null.
58    NullI31Ref,
59}
60
61impl TrapCode {
62    /// Returns a slice of all traps except `TrapCode::User` traps
63    pub const fn non_user_traps() -> &'static [TrapCode] {
64        &[
65            TrapCode::StackOverflow,
66            TrapCode::HeapOutOfBounds,
67            TrapCode::HeapMisaligned,
68            TrapCode::TableOutOfBounds,
69            TrapCode::IndirectCallToNull,
70            TrapCode::BadSignature,
71            TrapCode::IntegerOverflow,
72            TrapCode::IntegerDivisionByZero,
73            TrapCode::BadConversionToInteger,
74            TrapCode::UnreachableCodeReached,
75            TrapCode::Interrupt,
76            TrapCode::NullReference,
77        ]
78    }
79}
80
81impl Display for TrapCode {
82    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
83        use self::TrapCode::*;
84        let identifier = match *self {
85            StackOverflow => "stk_ovf",
86            HeapOutOfBounds => "heap_oob",
87            HeapMisaligned => "heap_misaligned",
88            TableOutOfBounds => "table_oob",
89            IndirectCallToNull => "icall_null",
90            BadSignature => "bad_sig",
91            IntegerOverflow => "int_ovf",
92            IntegerDivisionByZero => "int_divz",
93            BadConversionToInteger => "bad_toint",
94            UnreachableCodeReached => "unreachable",
95            Interrupt => "interrupt",
96            User(x) => return write!(f, "user{x}"),
97            NullReference => "null_reference",
98            NullI31Ref => "null_i31ref",
99        };
100        f.write_str(identifier)
101    }
102}
103
104impl FromStr for TrapCode {
105    type Err = ();
106
107    fn from_str(s: &str) -> Result<Self, Self::Err> {
108        use self::TrapCode::*;
109        match s {
110            "stk_ovf" => Ok(StackOverflow),
111            "heap_oob" => Ok(HeapOutOfBounds),
112            "heap_misaligned" => Ok(HeapMisaligned),
113            "table_oob" => Ok(TableOutOfBounds),
114            "icall_null" => Ok(IndirectCallToNull),
115            "bad_sig" => Ok(BadSignature),
116            "int_ovf" => Ok(IntegerOverflow),
117            "int_divz" => Ok(IntegerDivisionByZero),
118            "bad_toint" => Ok(BadConversionToInteger),
119            "unreachable" => Ok(UnreachableCodeReached),
120            "interrupt" => Ok(Interrupt),
121            "null_reference" => Ok(NullReference),
122            "null_i31ref" => Ok(NullI31Ref),
123            _ if s.starts_with("user") => s[4..].parse().map(User).map_err(|_| ()),
124            _ => Err(()),
125        }
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use alloc::string::ToString;
133
134    #[test]
135    fn display() {
136        for r in TrapCode::non_user_traps() {
137            let tc = *r;
138            assert_eq!(tc.to_string().parse(), Ok(tc));
139        }
140        assert_eq!("bogus".parse::<TrapCode>(), Err(()));
141
142        assert_eq!(TrapCode::User(17).to_string(), "user17");
143        assert_eq!("user22".parse(), Ok(TrapCode::User(22)));
144        assert_eq!("user".parse::<TrapCode>(), Err(()));
145        assert_eq!("user-1".parse::<TrapCode>(), Err(()));
146        assert_eq!("users".parse::<TrapCode>(), Err(()));
147    }
148}