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:
@@ -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!(),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
})?;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user