Deduplicate listings of traps in Wasmtime (#5299)

This commit replaces `wasmtime_environ::TrapCode` with `wasmtime::Trap`.
This is possible with past refactorings which slimmed down the `Trap`
definition in the `wasmtime` crate to a simple `enum`. This means that
there's one less place that all the various trap opcodes need to be
listed in Wasmtime.
This commit is contained in:
Alex Crichton
2022-11-18 16:04:38 -06:00
committed by GitHub
parent 9b7c5e316d
commit 7a31c5b07c
14 changed files with 178 additions and 248 deletions

View File

@@ -32,7 +32,7 @@ use std::sync::{Arc, Mutex};
use wasmparser::{FuncValidatorAllocations, FunctionBody};
use wasmtime_environ::{
AddressMapSection, CacheStore, CompileError, FilePos, FlagValue, FunctionBodyData, FunctionLoc,
InstructionAddressMap, ModuleTranslation, ModuleTypes, PtrSize, StackMapInformation, TrapCode,
InstructionAddressMap, ModuleTranslation, ModuleTypes, PtrSize, StackMapInformation, Trap,
TrapEncodingBuilder, TrapInformation, Tunables, VMOffsets, WasmFunctionInfo,
};
@@ -1003,18 +1003,18 @@ fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation {
TrapInformation {
code_offset: offset,
trap_code: 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(ALWAYS_TRAP_CODE) => TrapCode::AlwaysTrapAdapter,
ir::TrapCode::StackOverflow => Trap::StackOverflow,
ir::TrapCode::HeapOutOfBounds => Trap::MemoryOutOfBounds,
ir::TrapCode::HeapMisaligned => Trap::HeapMisaligned,
ir::TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
ir::TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
ir::TrapCode::BadSignature => Trap::BadSignature,
ir::TrapCode::IntegerOverflow => Trap::IntegerOverflow,
ir::TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
ir::TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
ir::TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
ir::TrapCode::Interrupt => Trap::Interrupt,
ir::TrapCode::User(ALWAYS_TRAP_CODE) => Trap::AlwaysTrapAdapter,
// these should never be emitted by wasmtime-cranelift
ir::TrapCode::User(_) => unreachable!(),

View File

@@ -2,6 +2,7 @@ use crate::obj::ELF_WASMTIME_TRAPS;
use object::write::{Object, StandardSegment};
use object::{Bytes, LittleEndian, SectionKind, U32Bytes};
use std::convert::TryFrom;
use std::fmt;
use std::ops::Range;
/// A helper structure to build the custom-encoded section of a wasmtime
@@ -26,29 +27,30 @@ pub struct TrapInformation {
pub code_offset: u32,
/// Code of the trap.
pub trap_code: TrapCode,
pub trap_code: Trap,
}
/// A trap code describing the reason for a trap.
///
/// All trap instructions have an explicit trap code.
// The code can be accessed from the c-api, where the possible values are
// translated into enum values defined there:
//
// * `wasm_trap_code` in c-api/src/trap.rs, and
// * `wasmtime_trap_code_enum` in c-api/include/wasmtime/trap.h.
//
// These need to be kept in sync.
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[repr(u8)]
pub enum TrapCode {
#[allow(missing_docs)]
pub enum Trap {
/// The current stack space was exhausted.
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,
/// An out-of-bounds memory access.
MemoryOutOfBounds,
/// 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.
/// An out-of-bounds access to a table.
TableOutOfBounds,
/// Indirect call to a null table entry.
@@ -70,15 +72,45 @@ pub enum TrapCode {
UnreachableCodeReached,
/// Execution has potentially run too long and may be interrupted.
/// This trap is resumable.
Interrupt,
/// Used for the component model when functions are lifted/lowered in a way
/// that generates a function that always traps.
/// When the `component-model` feature is enabled this trap represents a
/// function that was `canon lift`'d, then `canon lower`'d, then called.
/// This combination of creation of a function in the component model
/// generates a function that always traps and, when called, produces this
/// flavor of trap.
AlwaysTrapAdapter,
// if adding a variant here be sure to update the `check!` macro below
/// When wasm code is configured to consume fuel and it runs out of fuel
/// then this trap will be raised.
OutOfFuel,
}
impl fmt::Display for Trap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Trap::*;
let desc = match self {
StackOverflow => "call stack exhausted",
MemoryOutOfBounds => "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 => "wasm `unreachable` instruction executed",
Interrupt => "interrupt",
AlwaysTrapAdapter => "degenerate component adapter called",
OutOfFuel => "all fuel consumed by WebAssembly",
};
write!(f, "wasm trap: {desc}")
}
}
impl std::error::Error for Trap {}
impl TrapEncodingBuilder {
/// Appends trap information about a function into this section.
///
@@ -136,7 +168,7 @@ impl TrapEncodingBuilder {
/// The `section` provided is expected to have been built by
/// `TrapEncodingBuilder` above. Additionally the `offset` should be a relative
/// offset within the text section of the compilation image.
pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<TrapCode> {
pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<Trap> {
let mut section = Bytes(section);
// NB: this matches the encoding written by `append_to` above.
let count = section.read::<U32Bytes<LittleEndian>>().ok()?;
@@ -164,16 +196,16 @@ pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<TrapCode> {
// FIXME: this could use some sort of derive-like thing to avoid having to
// deduplicate the names here.
//
// This simply converts from the `trap`, a `u8`, to the `TrapCode` enum.
// This simply converts from the `trap`, a `u8`, to the `Trap` enum.
macro_rules! check {
($($name:ident)*) => ($(if trap == TrapCode::$name as u8 {
return Some(TrapCode::$name);
($($name:ident)*) => ($(if trap == Trap::$name as u8 {
return Some(Trap::$name);
})*);
}
check! {
StackOverflow
HeapOutOfBounds
MemoryOutOfBounds
HeapMisaligned
TableOutOfBounds
IndirectCallToNull
@@ -184,6 +216,7 @@ pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<TrapCode> {
UnreachableCodeReached
Interrupt
AlwaysTrapAdapter
OutOfFuel
}
if cfg!(debug_assertions) {

View File

@@ -30,7 +30,7 @@ use wasmtime_environ::{
packed_option::ReservedValue, DataIndex, DefinedGlobalIndex, DefinedMemoryIndex,
DefinedTableIndex, ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex,
GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex,
TableInitialization, TrapCode, VMOffsets, WasmType,
TableInitialization, Trap, VMOffsets, WasmType,
};
mod allocator;
@@ -580,7 +580,7 @@ impl Instance {
dst: u32,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
// TODO: this `clone()` shouldn't be necessary but is used for now to
// inform `rustc` that the lifetime of the elements here are
// disconnected from the lifetime of `self`.
@@ -602,7 +602,7 @@ impl Instance {
dst: u32,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
let table = unsafe { &mut *self.get_table(table_index) };
@@ -612,7 +612,7 @@ impl Instance {
.and_then(|s| s.get(..usize::try_from(len).unwrap()))
{
Some(elements) => elements,
None => return Err(TrapCode::TableOutOfBounds),
None => return Err(Trap::TableOutOfBounds),
};
match table.element_type() {
@@ -662,7 +662,7 @@ impl Instance {
src_index: MemoryIndex,
src: u64,
len: u64,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
// https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
let src_mem = self.get_memory(src_index);
@@ -684,8 +684,8 @@ impl Instance {
Ok(())
}
fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, TrapCode> {
let oob = || TrapCode::HeapOutOfBounds;
fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, Trap> {
let oob = || Trap::MemoryOutOfBounds;
let end = ptr
.checked_add(len)
.and_then(|i| usize::try_from(i).ok())
@@ -708,7 +708,7 @@ impl Instance {
dst: u64,
val: u8,
len: u64,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let memory = self.get_memory(memory_index);
let dst = self.validate_inbounds(memory.current_length(), dst, len)?;
@@ -738,7 +738,7 @@ impl Instance {
dst: u64,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let range = match self.module().passive_data_map.get(&data_index).cloned() {
Some(range) if !self.dropped_data.contains(data_index) => range,
_ => 0..0,
@@ -757,7 +757,7 @@ impl Instance {
dst: u64,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init
let memory = self.get_memory(memory_index);

View File

@@ -13,8 +13,8 @@ use std::sync::Arc;
use thiserror::Error;
use wasmtime_environ::{
DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
MemoryInitializer, Module, PrimaryMap, TableInitialization, TableInitializer, TrapCode,
VMOffsets, WasmType, WASM_PAGE_SIZE,
MemoryInitializer, Module, PrimaryMap, TableInitialization, TableInitializer, Trap, VMOffsets,
WasmType, WASM_PAGE_SIZE,
};
#[cfg(feature = "pooling-allocator")]
@@ -105,7 +105,7 @@ pub enum InstantiationError {
/// A trap ocurred during instantiation, after linking.
#[error("Trap occurred during instantiation")]
Trap(TrapCode),
Trap(Trap),
/// A limit on how many instances are supported has been reached.
#[error("Limit of {0} concurrent instances has been reached")]
@@ -386,7 +386,7 @@ fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<(), I
},
);
if !ok {
return Err(InstantiationError::Trap(TrapCode::HeapOutOfBounds));
return Err(InstantiationError::Trap(Trap::MemoryOutOfBounds));
}
Ok(())

View File

@@ -63,7 +63,7 @@ use anyhow::Result;
use std::mem;
use std::ptr::{self, NonNull};
use wasmtime_environ::{
DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TrapCode,
DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap,
};
/// Actually public trampolines which are used by the runtime as the entrypoint
@@ -228,7 +228,7 @@ unsafe fn table_fill(
// `VMCallerCheckedAnyfunc` until we look at the table's element type.
val: *mut u8,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let instance = (*vmctx).instance_mut();
let table_index = TableIndex::from_u32(table_index);
let table = &mut *instance.get_table(table_index);
@@ -259,7 +259,7 @@ unsafe fn table_copy(
dst: u32,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let dst_table_index = TableIndex::from_u32(dst_table_index);
let src_table_index = TableIndex::from_u32(src_table_index);
let instance = (*vmctx).instance_mut();
@@ -278,7 +278,7 @@ unsafe fn table_init(
dst: u32,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let table_index = TableIndex::from_u32(table_index);
let elem_index = ElemIndex::from_u32(elem_index);
let instance = (*vmctx).instance_mut();
@@ -300,7 +300,7 @@ unsafe fn memory_copy(
src_index: u32,
src: u64,
len: u64,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let src_index = MemoryIndex::from_u32(src_index);
let dst_index = MemoryIndex::from_u32(dst_index);
let instance = (*vmctx).instance_mut();
@@ -314,7 +314,7 @@ unsafe fn memory_fill(
dst: u64,
val: u32,
len: u64,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let memory_index = MemoryIndex::from_u32(memory_index);
let instance = (*vmctx).instance_mut();
instance.memory_fill(memory_index, dst, val as u8, len)
@@ -328,7 +328,7 @@ unsafe fn memory_init(
dst: u64,
src: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
let memory_index = MemoryIndex::from_u32(memory_index);
let data_index = DataIndex::from_u32(data_index);
let instance = (*vmctx).instance_mut();
@@ -498,14 +498,14 @@ unsafe fn validate_atomic_addr(
addr: u64,
access_size: u64,
access_alignment: u64,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
debug_assert!(access_alignment.is_power_of_two());
ensure!(addr % access_alignment == 0, TrapCode::HeapMisaligned);
ensure!(addr % access_alignment == 0, Trap::HeapMisaligned);
let length = u64::try_from(instance.get_memory(memory).current_length()).unwrap();
ensure!(
addr.saturating_add(access_size) < length,
TrapCode::HeapOutOfBounds
Trap::MemoryOutOfBounds
);
Ok(())

View File

@@ -8,7 +8,7 @@ use anyhow::{bail, format_err, Error, Result};
use std::convert::{TryFrom, TryInto};
use std::ops::Range;
use std::ptr;
use wasmtime_environ::{TablePlan, TrapCode, WasmType, FUNCREF_INIT_BIT, FUNCREF_MASK};
use wasmtime_environ::{TablePlan, Trap, WasmType, FUNCREF_INIT_BIT, FUNCREF_MASK};
/// An element going into or coming out of a table.
///
@@ -267,7 +267,7 @@ impl Table {
&mut self,
dst: u32,
items: impl ExactSizeIterator<Item = *mut VMCallerCheckedAnyfunc>,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
assert!(self.element_type() == TableElementType::Func);
let elements = match self
@@ -276,7 +276,7 @@ impl Table {
.and_then(|s| s.get_mut(..items.len()))
{
Some(elements) => elements,
None => return Err(TrapCode::TableOutOfBounds),
None => return Err(Trap::TableOutOfBounds),
};
for (item, slot) in items.zip(elements) {
@@ -290,14 +290,14 @@ impl Table {
/// Fill `table[dst..dst + len]` with `val`.
///
/// Returns a trap error on out-of-bounds accesses.
pub fn fill(&mut self, dst: u32, val: TableElement, len: u32) -> Result<(), TrapCode> {
pub fn fill(&mut self, dst: u32, val: TableElement, len: u32) -> Result<(), Trap> {
let start = dst as usize;
let end = start
.checked_add(len as usize)
.ok_or_else(|| TrapCode::TableOutOfBounds)?;
.ok_or_else(|| Trap::TableOutOfBounds)?;
if end > self.size() as usize {
return Err(TrapCode::TableOutOfBounds);
return Err(Trap::TableOutOfBounds);
}
debug_assert!(self.type_matches(&val));
@@ -412,7 +412,7 @@ impl Table {
dst_index: u32,
src_index: u32,
len: u32,
) -> Result<(), TrapCode> {
) -> Result<(), Trap> {
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-copy
if src_index
@@ -422,7 +422,7 @@ impl Table {
.checked_add(len)
.map_or(true, |m| m > (*dst_table).size())
{
return Err(TrapCode::TableOutOfBounds);
return Err(Trap::TableOutOfBounds);
}
debug_assert!(

View File

@@ -10,7 +10,6 @@ use std::cell::{Cell, UnsafeCell};
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Once;
use wasmtime_environ::TrapCode;
pub use self::backtrace::Backtrace;
pub use self::tls::{tls_eager_initialize, TlsRestore};
@@ -112,7 +111,7 @@ pub unsafe fn raise_user_trap(error: Error, needs_backtrace: bool) -> ! {
/// Only safe to call when wasm code is on the stack, aka `catch_traps` must
/// have been previously called. Additionally no Rust destructors can be on the
/// stack. They will be skipped and not executed.
pub unsafe fn raise_lib_trap(trap: TrapCode) -> ! {
pub unsafe fn raise_lib_trap(trap: wasmtime_environ::Trap) -> ! {
raise_trap(TrapReason::Wasm(trap))
}
@@ -153,7 +152,7 @@ pub enum TrapReason {
Jit(usize),
/// A trap raised from a wasm libcall
Wasm(TrapCode),
Wasm(wasmtime_environ::Trap),
}
impl TrapReason {
@@ -185,8 +184,8 @@ impl From<Error> for TrapReason {
}
}
impl From<TrapCode> for TrapReason {
fn from(code: TrapCode) -> Self {
impl From<wasmtime_environ::Trap> for TrapReason {
fn from(code: wasmtime_environ::Trap) -> Self {
TrapReason::Wasm(code)
}
}

View File

@@ -1,7 +1,7 @@
use crate::component::func::{Memory, MemoryMut, Options};
use crate::component::storage::slice_to_storage_mut;
use crate::component::{ComponentNamedList, ComponentType, Lift, Lower, Type, Val};
use crate::{AsContextMut, StoreContextMut, Trap, ValRaw};
use crate::{AsContextMut, StoreContextMut, ValRaw};
use anyhow::{anyhow, bail, Context, Result};
use std::any::Any;
use std::mem::{self, MaybeUninit};
@@ -270,7 +270,7 @@ fn validate_inbounds<T: ComponentType>(memory: &[u8], ptr: &ValRaw) -> Result<us
unsafe fn handle_result(func: impl FnOnce() -> Result<()>) {
match panic::catch_unwind(AssertUnwindSafe(func)) {
Ok(Ok(())) => {}
Ok(Err(e)) => Trap::raise(e),
Ok(Err(e)) => crate::trap::raise(e),
Err(e) => wasmtime_runtime::resume_panic(e),
}
}

View File

@@ -2,7 +2,7 @@ use crate::store::{StoreData, StoreOpaque, Stored};
use crate::trampoline::{generate_global_export, generate_table_export};
use crate::{
AsContext, AsContextMut, Engine, ExternRef, ExternType, Func, GlobalType, Memory, Mutability,
SharedMemory, TableType, Trap, Val, ValType,
SharedMemory, TableType, Val, ValType,
};
use anyhow::{anyhow, bail, Result};
use std::mem;
@@ -462,9 +462,7 @@ impl Table {
let init = init.into_table_element(store, ty.element())?;
unsafe {
let table = Table::from_wasmtime_table(wasmtime_export, store);
(*table.wasmtime_table(store, std::iter::empty()))
.fill(0, init, ty.minimum())
.map_err(|c| Trap::from_env(c))?;
(*table.wasmtime_table(store, std::iter::empty())).fill(0, init, ty.minimum())?;
Ok(table)
}
@@ -652,8 +650,7 @@ impl Table {
let src_range = src_index..(src_index.checked_add(len).unwrap_or(u32::MAX));
let src_table = src_table.wasmtime_table(store, src_range);
unsafe {
runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)
.map_err(|c| Trap::from_env(c))?;
runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)?;
}
Ok(())
}
@@ -681,9 +678,7 @@ impl Table {
let table = self.wasmtime_table(store, std::iter::empty());
unsafe {
(*table)
.fill(dst, val, len)
.map_err(|c| Trap::from_env(c))?;
(*table).fill(dst, val, len)?;
}
Ok(())

View File

@@ -1,7 +1,7 @@
use crate::store::{StoreData, StoreOpaque, Stored};
use crate::{
AsContext, AsContextMut, CallHook, Engine, Extern, FuncType, Instance, StoreContext,
StoreContextMut, Trap, Val, ValRaw, ValType,
StoreContextMut, Val, ValRaw, ValType,
};
use anyhow::{bail, Context as _, Error, Result};
use std::future::Future;
@@ -343,6 +343,8 @@ impl Func {
///
/// For more information about errors in Wasmtime see the [`Trap`]
/// documentation.
///
/// [`Trap`]: crate::Trap
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
pub fn new<T>(
@@ -581,6 +583,8 @@ impl Func {
/// For more information about errors in Wasmtime see the [`Trap`]
/// documentation.
///
/// [`Trap`]: crate::Trap
///
/// # Examples
///
/// First up we can see how simple wasm imports can be implemented, such
@@ -816,6 +820,8 @@ impl Func {
/// Errors typically indicate that execution of WebAssembly was halted
/// mid-way and did not complete after the error condition happened.
///
/// [`Trap`]: crate::Trap
///
/// # Panics
///
/// This function will panic if called on a function belonging to an async
@@ -1305,7 +1311,7 @@ pub(crate) fn invoke_wasm_and_catch_traps<T>(
);
exit_wasm(store, exit);
store.0.call_hook(CallHook::ReturningFromWasm)?;
result.map_err(|t| Trap::from_runtime_box(store.0, t))
result.map_err(|t| crate::trap::from_runtime_box(store.0, t))
}
}
@@ -1947,7 +1953,7 @@ macro_rules! impl_into_func {
match result {
CallResult::Ok(val) => val,
CallResult::Trap(err) => Trap::raise(err),
CallResult::Trap(err) => crate::trap::raise(err),
CallResult::Panic(panic) => wasmtime_runtime::resume_panic(panic),
}
}

View File

@@ -3,7 +3,7 @@ use crate::store::{InstanceId, StoreOpaque, Stored};
use crate::types::matching;
use crate::{
AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, SharedMemory,
StoreContextMut, Table, Trap, TypedFunc,
StoreContextMut, Table, TypedFunc,
};
use anyhow::{anyhow, bail, Context, Error, Result};
use std::mem;
@@ -91,6 +91,8 @@ impl Instance {
/// check for trap errors, you can use `error.downcast::<Trap>()`. For more
/// about error handling see the [`Trap`] documentation.
///
/// [`Trap`]: crate::Trap
///
/// # Panics
///
/// This function will panic if called with a store associated with a
@@ -325,7 +327,7 @@ impl Instance {
)
.map_err(|e| -> Error {
match e {
InstantiationError::Trap(trap) => Trap::from_env(trap).into(),
InstantiationError::Trap(trap) => trap.into(),
other => other.into(),
}
})?;

View File

@@ -3,14 +3,13 @@
use crate::code::CodeObject;
#[cfg(feature = "component-model")]
use crate::component::Component;
use crate::{FrameInfo, Module};
use crate::{FrameInfo, Module, Trap};
use once_cell::sync::Lazy;
use std::collections::btree_map::Entry;
use std::{
collections::BTreeMap,
sync::{Arc, RwLock},
};
use wasmtime_environ::TrapCode;
use wasmtime_jit::CodeMemory;
use wasmtime_runtime::{ModuleInfo, VMCallerCheckedAnyfunc, VMTrampoline};
@@ -132,7 +131,7 @@ impl ModuleRegistry {
}
/// Fetches trap information about a program counter in a backtrace.
pub fn lookup_trap_code(&self, pc: usize) -> Option<TrapCode> {
pub fn lookup_trap_code(&self, pc: usize) -> Option<Trap> {
let (code, offset) = self.code(pc)?;
wasmtime_environ::lookup_trap_code(code.code.code_memory().trap_data(), offset)
}

View File

@@ -1,6 +1,6 @@
//! Support for a calling of an imported function.
use crate::{Engine, FuncType, Trap, ValRaw};
use crate::{Engine, FuncType, ValRaw};
use anyhow::Result;
use std::panic::{self, AssertUnwindSafe};
use std::ptr::NonNull;
@@ -56,7 +56,7 @@ unsafe extern "C" fn stub_fn<F>(
// call-site, which gets unwrapped in `Trap::from_runtime` later on as we
// convert from the internal `Trap` type to our own `Trap` type in this
// crate.
Ok(Err(trap)) => Trap::raise(trap.into()),
Ok(Err(trap)) => crate::trap::raise(trap.into()),
// And finally if the imported function panicked, then we trigger the
// form of unwinding that's safe to jump over wasm code on all

View File

@@ -2,7 +2,7 @@ use crate::store::StoreOpaque;
use crate::Module;
use anyhow::Error;
use std::fmt;
use wasmtime_environ::{EntityRef, FilePos, TrapCode};
use wasmtime_environ::{EntityRef, FilePos};
use wasmtime_jit::{demangle_function_name, demangle_function_name_or_index};
/// Representation of a WebAssembly trap and what caused it to occur.
@@ -65,66 +65,8 @@ use wasmtime_jit::{demangle_function_name, demangle_function_name_or_index};
/// # Ok(())
/// # }
/// ```
//
// The code can be accessed from the c-api, where the possible values are translated
// into enum values defined there:
//
// * `wasm_trap_code` in c-api/src/trap.rs, and
// * `wasmtime_trap_code_enum` in c-api/include/wasmtime/trap.h.
//
// These need to be kept in sync.
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum Trap {
/// The current stack space was exhausted.
StackOverflow,
pub use wasmtime_environ::Trap;
/// An out-of-bounds memory access.
MemoryOutOfBounds,
/// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
HeapMisaligned,
/// An out-of-bounds access to a table.
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.
Interrupt,
/// When the `component-model` feature is enabled this trap represents a
/// function that was `canon lift`'d, then `canon lower`'d, then called.
/// This combination of creation of a function in the component model
/// generates a function that always traps and, when called, produces this
/// flavor of trap.
AlwaysTrapAdapter,
/// When wasm code is configured to consume fuel and it runs out of fuel
/// then this trap will be raised.
///
/// For more information see
/// [`Config::consume_fuel`](crate::Config::consume_fuel).
OutOfFuel,
}
impl Trap {
// Same safety requirements and caveats as
// `wasmtime_runtime::raise_user_trap`.
pub(crate) unsafe fn raise(error: anyhow::Error) -> ! {
@@ -163,12 +105,10 @@ impl Trap {
let code = store
.modules()
.lookup_trap_code(pc)
.unwrap_or(TrapCode::StackOverflow);
(Trap::from_env(code).into(), Some(pc))
}
wasmtime_runtime::TrapReason::Wasm(trap_code) => {
(Trap::from_env(trap_code).into(), None)
.unwrap_or(Trap::StackOverflow);
(code.into(), Some(pc))
}
wasmtime_runtime::TrapReason::Wasm(trap_code) => (trap_code.into(), None),
};
match backtrace {
Some(bt) => {
@@ -183,50 +123,6 @@ impl Trap {
}
}
/// Panics if `code` is `TrapCode::User`.
pub(crate) fn from_env(code: TrapCode) -> Self {
match code {
TrapCode::StackOverflow => Trap::StackOverflow,
TrapCode::HeapOutOfBounds => Trap::MemoryOutOfBounds,
TrapCode::HeapMisaligned => Trap::HeapMisaligned,
TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
TrapCode::BadSignature => Trap::BadSignature,
TrapCode::IntegerOverflow => Trap::IntegerOverflow,
TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
TrapCode::Interrupt => Trap::Interrupt,
TrapCode::AlwaysTrapAdapter => Trap::AlwaysTrapAdapter,
}
}
}
impl fmt::Display for Trap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Trap::*;
let desc = match self {
StackOverflow => "call stack exhausted",
MemoryOutOfBounds => "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 => "wasm `unreachable` instruction executed",
Interrupt => "interrupt",
AlwaysTrapAdapter => "degenerate component adapter called",
OutOfFuel => "all fuel consumed by WebAssembly",
};
write!(f, "wasm trap: {desc}")
}
}
impl std::error::Error for Trap {}
/// Representation of a backtrace of function frames in a WebAssembly module for
/// where an error happened.
///