From 728493e9341668ec34732520dd915f889c214721 Mon Sep 17 00:00:00 2001 From: Leonardo Yvens Date: Fri, 23 Oct 2020 18:24:43 -0300 Subject: [PATCH] Add non-exhaustive wasmtime::TrapCode --- crates/wasmtime/src/trap.rs | 119 ++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 24 deletions(-) diff --git a/crates/wasmtime/src/trap.rs b/crates/wasmtime/src/trap.rs index ee306b4a3ec5..4426abcf7df9 100644 --- a/crates/wasmtime/src/trap.rs +++ b/crates/wasmtime/src/trap.rs @@ -3,7 +3,7 @@ use crate::FrameInfo; use backtrace::Backtrace; use std::fmt; use std::sync::Arc; -use wasmtime_environ::ir::TrapCode; +use wasmtime_environ::ir; /// A struct representing an aborted instruction execution, with a message /// indicating the cause. @@ -31,32 +31,103 @@ enum TrapReason { impl fmt::Display for TrapReason { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use wasmtime_environ::ir::TrapCode::*; match self { TrapReason::Message(s) => write!(f, "{}", s), TrapReason::I32Exit(status) => write!(f, "Exited with i32 exit status {}", status), TrapReason::Error(e) => write!(f, "{}", e), - TrapReason::InstructionTrap(code) => { - let desc = match code { - StackOverflow => "call stack exhausted", - HeapOutOfBounds => "out of bounds memory access", - HeapMisaligned => "misaligned memory access", - TableOutOfBounds => "undefined element: out of bounds table access", - IndirectCallToNull => "uninitialized element", - BadSignature => "indirect call type mismatch", - IntegerOverflow => "integer overflow", - IntegerDivisionByZero => "integer divide by zero", - BadConversionToInteger => "invalid conversion to integer", - UnreachableCodeReached => "unreachable", - Interrupt => "interrupt", - User(_) => unreachable!(), - }; - write!(f, "wasm trap: {}", desc) - } + TrapReason::InstructionTrap(code) => write!(f, "wasm trap: {}", code), } } } +/// A trap code describing the reason for a trap. +/// +/// All trap instructions have an explicit trap code. +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum TrapCode { + /// The current stack space was exhausted. + /// + /// On some platforms, a stack overflow may also be indicated by a segmentation fault from the + /// stack guard page. + StackOverflow, + + /// A `heap_addr` instruction detected an out-of-bounds error. + /// + /// Note that not all out-of-bounds heap accesses are reported this way; + /// some are detected by a segmentation fault on the heap unmapped or + /// offset-guard pages. + HeapOutOfBounds, + + /// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address. + HeapMisaligned, + + /// A `table_addr` instruction detected an out-of-bounds error. + TableOutOfBounds, + + /// Indirect call to a null table entry. + IndirectCallToNull, + + /// Signature mismatch on indirect call. + BadSignature, + + /// An integer arithmetic operation caused an overflow. + IntegerOverflow, + + /// An integer division by zero. + IntegerDivisionByZero, + + /// Failed float-to-int conversion. + BadConversionToInteger, + + /// Code that was supposed to have been unreachable was reached. + UnreachableCodeReached, + + /// Execution has potentially run too long and may be interrupted. + /// This trap is resumable. + Interrupt, +} + +impl TrapCode { + /// Panics if `code` is `ir::TrapCode::User`. + fn from_non_user(code: ir::TrapCode) -> Self { + match code { + ir::TrapCode::StackOverflow => TrapCode::StackOverflow, + ir::TrapCode::HeapOutOfBounds => TrapCode::HeapOutOfBounds, + ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned, + ir::TrapCode::TableOutOfBounds => TrapCode::TableOutOfBounds, + ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull, + ir::TrapCode::BadSignature => TrapCode::BadSignature, + ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow, + ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero, + ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger, + ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached, + ir::TrapCode::Interrupt => TrapCode::Interrupt, + ir::TrapCode::User(_) => panic!("Called `TrapCode::from_non_user` with user code"), + } + } +} + +impl fmt::Display for TrapCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use TrapCode::*; + let desc = match self { + StackOverflow => "call stack exhausted", + HeapOutOfBounds => "out of bounds memory access", + HeapMisaligned => "misaligned memory access", + TableOutOfBounds => "undefined element: out of bounds table access", + IndirectCallToNull => "uninitialized element", + BadSignature => "indirect call type mismatch", + IntegerOverflow => "integer overflow", + IntegerDivisionByZero => "integer divide by zero", + BadConversionToInteger => "invalid conversion to integer", + UnreachableCodeReached => "unreachable", + Interrupt => "interrupt", + }; + write!(f, "{}", desc) + } +} + struct TrapInner { reason: TrapReason, wasm_trace: Vec, @@ -104,9 +175,9 @@ impl Trap { let mut code = info .lookup_trap_info(pc) .map(|info| info.trap_code) - .unwrap_or(TrapCode::StackOverflow); - if maybe_interrupted && code == TrapCode::StackOverflow { - code = TrapCode::Interrupt; + .unwrap_or(ir::TrapCode::StackOverflow); + if maybe_interrupted && code == ir::TrapCode::StackOverflow { + code = ir::TrapCode::Interrupt; } Trap::new_wasm(&info, Some(pc), code, backtrace) } @@ -124,10 +195,10 @@ impl Trap { fn new_wasm( info: &GlobalFrameInfo, trap_pc: Option, - code: TrapCode, + code: ir::TrapCode, backtrace: Backtrace, ) -> Self { - assert!(!matches!(code, TrapCode::User(_))); + let code = TrapCode::from_non_user(code); Trap::new_with_trace(info, trap_pc, TrapReason::InstructionTrap(code), backtrace) }