Skip to content

Commit 7a31c5b

Browse files
authored
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.
1 parent 9b7c5e3 commit 7a31c5b

File tree

14 files changed

+179
-249
lines changed

14 files changed

+179
-249
lines changed

crates/cranelift/src/compiler.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use std::sync::{Arc, Mutex};
3232
use wasmparser::{FuncValidatorAllocations, FunctionBody};
3333
use wasmtime_environ::{
3434
AddressMapSection, CacheStore, CompileError, FilePos, FlagValue, FunctionBodyData, FunctionLoc,
35-
InstructionAddressMap, ModuleTranslation, ModuleTypes, PtrSize, StackMapInformation, TrapCode,
35+
InstructionAddressMap, ModuleTranslation, ModuleTypes, PtrSize, StackMapInformation, Trap,
3636
TrapEncodingBuilder, TrapInformation, Tunables, VMOffsets, WasmFunctionInfo,
3737
};
3838

@@ -1003,18 +1003,18 @@ fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation {
10031003
TrapInformation {
10041004
code_offset: offset,
10051005
trap_code: match code {
1006-
ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
1007-
ir::TrapCode::HeapOutOfBounds => TrapCode::HeapOutOfBounds,
1008-
ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned,
1009-
ir::TrapCode::TableOutOfBounds => TrapCode::TableOutOfBounds,
1010-
ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
1011-
ir::TrapCode::BadSignature => TrapCode::BadSignature,
1012-
ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow,
1013-
ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero,
1014-
ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger,
1015-
ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached,
1016-
ir::TrapCode::Interrupt => TrapCode::Interrupt,
1017-
ir::TrapCode::User(ALWAYS_TRAP_CODE) => TrapCode::AlwaysTrapAdapter,
1006+
ir::TrapCode::StackOverflow => Trap::StackOverflow,
1007+
ir::TrapCode::HeapOutOfBounds => Trap::MemoryOutOfBounds,
1008+
ir::TrapCode::HeapMisaligned => Trap::HeapMisaligned,
1009+
ir::TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
1010+
ir::TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
1011+
ir::TrapCode::BadSignature => Trap::BadSignature,
1012+
ir::TrapCode::IntegerOverflow => Trap::IntegerOverflow,
1013+
ir::TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
1014+
ir::TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
1015+
ir::TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
1016+
ir::TrapCode::Interrupt => Trap::Interrupt,
1017+
ir::TrapCode::User(ALWAYS_TRAP_CODE) => Trap::AlwaysTrapAdapter,
10181018

10191019
// these should never be emitted by wasmtime-cranelift
10201020
ir::TrapCode::User(_) => unreachable!(),

crates/environ/src/trap_encoding.rs

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::obj::ELF_WASMTIME_TRAPS;
22
use object::write::{Object, StandardSegment};
33
use object::{Bytes, LittleEndian, SectionKind, U32Bytes};
44
use std::convert::TryFrom;
5+
use std::fmt;
56
use std::ops::Range;
67

78
/// A helper structure to build the custom-encoded section of a wasmtime
@@ -26,29 +27,30 @@ pub struct TrapInformation {
2627
pub code_offset: u32,
2728

2829
/// Code of the trap.
29-
pub trap_code: TrapCode,
30+
pub trap_code: Trap,
3031
}
3132

32-
/// A trap code describing the reason for a trap.
33-
///
34-
/// All trap instructions have an explicit trap code.
33+
// The code can be accessed from the c-api, where the possible values are
34+
// translated into enum values defined there:
35+
//
36+
// * `wasm_trap_code` in c-api/src/trap.rs, and
37+
// * `wasmtime_trap_code_enum` in c-api/include/wasmtime/trap.h.
38+
//
39+
// These need to be kept in sync.
40+
#[non_exhaustive]
3541
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
36-
#[repr(u8)]
37-
pub enum TrapCode {
42+
#[allow(missing_docs)]
43+
pub enum Trap {
3844
/// The current stack space was exhausted.
3945
StackOverflow,
4046

41-
/// A `heap_addr` instruction detected an out-of-bounds error.
42-
///
43-
/// Note that not all out-of-bounds heap accesses are reported this way;
44-
/// some are detected by a segmentation fault on the heap unmapped or
45-
/// offset-guard pages.
46-
HeapOutOfBounds,
47+
/// An out-of-bounds memory access.
48+
MemoryOutOfBounds,
4749

4850
/// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
4951
HeapMisaligned,
5052

51-
/// A `table_addr` instruction detected an out-of-bounds error.
53+
/// An out-of-bounds access to a table.
5254
TableOutOfBounds,
5355

5456
/// Indirect call to a null table entry.
@@ -70,15 +72,45 @@ pub enum TrapCode {
7072
UnreachableCodeReached,
7173

7274
/// Execution has potentially run too long and may be interrupted.
73-
/// This trap is resumable.
7475
Interrupt,
7576

76-
/// Used for the component model when functions are lifted/lowered in a way
77-
/// that generates a function that always traps.
77+
/// When the `component-model` feature is enabled this trap represents a
78+
/// function that was `canon lift`'d, then `canon lower`'d, then called.
79+
/// This combination of creation of a function in the component model
80+
/// generates a function that always traps and, when called, produces this
81+
/// flavor of trap.
7882
AlwaysTrapAdapter,
79-
// if adding a variant here be sure to update the `check!` macro below
83+
84+
/// When wasm code is configured to consume fuel and it runs out of fuel
85+
/// then this trap will be raised.
86+
OutOfFuel,
8087
}
8188

89+
impl fmt::Display for Trap {
90+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91+
use Trap::*;
92+
93+
let desc = match self {
94+
StackOverflow => "call stack exhausted",
95+
MemoryOutOfBounds => "out of bounds memory access",
96+
HeapMisaligned => "misaligned memory access",
97+
TableOutOfBounds => "undefined element: out of bounds table access",
98+
IndirectCallToNull => "uninitialized element",
99+
BadSignature => "indirect call type mismatch",
100+
IntegerOverflow => "integer overflow",
101+
IntegerDivisionByZero => "integer divide by zero",
102+
BadConversionToInteger => "invalid conversion to integer",
103+
UnreachableCodeReached => "wasm `unreachable` instruction executed",
104+
Interrupt => "interrupt",
105+
AlwaysTrapAdapter => "degenerate component adapter called",
106+
OutOfFuel => "all fuel consumed by WebAssembly",
107+
};
108+
write!(f, "wasm trap: {desc}")
109+
}
110+
}
111+
112+
impl std::error::Error for Trap {}
113+
82114
impl TrapEncodingBuilder {
83115
/// Appends trap information about a function into this section.
84116
///
@@ -136,7 +168,7 @@ impl TrapEncodingBuilder {
136168
/// The `section` provided is expected to have been built by
137169
/// `TrapEncodingBuilder` above. Additionally the `offset` should be a relative
138170
/// offset within the text section of the compilation image.
139-
pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<TrapCode> {
171+
pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<Trap> {
140172
let mut section = Bytes(section);
141173
// NB: this matches the encoding written by `append_to` above.
142174
let count = section.read::<U32Bytes<LittleEndian>>().ok()?;
@@ -164,16 +196,16 @@ pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<TrapCode> {
164196
// FIXME: this could use some sort of derive-like thing to avoid having to
165197
// deduplicate the names here.
166198
//
167-
// This simply converts from the `trap`, a `u8`, to the `TrapCode` enum.
199+
// This simply converts from the `trap`, a `u8`, to the `Trap` enum.
168200
macro_rules! check {
169-
($($name:ident)*) => ($(if trap == TrapCode::$name as u8 {
170-
return Some(TrapCode::$name);
201+
($($name:ident)*) => ($(if trap == Trap::$name as u8 {
202+
return Some(Trap::$name);
171203
})*);
172204
}
173205

174206
check! {
175207
StackOverflow
176-
HeapOutOfBounds
208+
MemoryOutOfBounds
177209
HeapMisaligned
178210
TableOutOfBounds
179211
IndirectCallToNull
@@ -184,6 +216,7 @@ pub fn lookup_trap_code(section: &[u8], offset: usize) -> Option<TrapCode> {
184216
UnreachableCodeReached
185217
Interrupt
186218
AlwaysTrapAdapter
219+
OutOfFuel
187220
}
188221

189222
if cfg!(debug_assertions) {

crates/runtime/src/instance.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use wasmtime_environ::{
3030
packed_option::ReservedValue, DataIndex, DefinedGlobalIndex, DefinedMemoryIndex,
3131
DefinedTableIndex, ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex,
3232
GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex,
33-
TableInitialization, TrapCode, VMOffsets, WasmType,
33+
TableInitialization, Trap, VMOffsets, WasmType,
3434
};
3535

3636
mod allocator;
@@ -580,7 +580,7 @@ impl Instance {
580580
dst: u32,
581581
src: u32,
582582
len: u32,
583-
) -> Result<(), TrapCode> {
583+
) -> Result<(), Trap> {
584584
// TODO: this `clone()` shouldn't be necessary but is used for now to
585585
// inform `rustc` that the lifetime of the elements here are
586586
// disconnected from the lifetime of `self`.
@@ -602,7 +602,7 @@ impl Instance {
602602
dst: u32,
603603
src: u32,
604604
len: u32,
605-
) -> Result<(), TrapCode> {
605+
) -> Result<(), Trap> {
606606
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
607607

608608
let table = unsafe { &mut *self.get_table(table_index) };
@@ -612,7 +612,7 @@ impl Instance {
612612
.and_then(|s| s.get(..usize::try_from(len).unwrap()))
613613
{
614614
Some(elements) => elements,
615-
None => return Err(TrapCode::TableOutOfBounds),
615+
None => return Err(Trap::TableOutOfBounds),
616616
};
617617

618618
match table.element_type() {
@@ -662,7 +662,7 @@ impl Instance {
662662
src_index: MemoryIndex,
663663
src: u64,
664664
len: u64,
665-
) -> Result<(), TrapCode> {
665+
) -> Result<(), Trap> {
666666
// https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
667667

668668
let src_mem = self.get_memory(src_index);
@@ -684,8 +684,8 @@ impl Instance {
684684
Ok(())
685685
}
686686

687-
fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, TrapCode> {
688-
let oob = || TrapCode::HeapOutOfBounds;
687+
fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, Trap> {
688+
let oob = || Trap::MemoryOutOfBounds;
689689
let end = ptr
690690
.checked_add(len)
691691
.and_then(|i| usize::try_from(i).ok())
@@ -708,7 +708,7 @@ impl Instance {
708708
dst: u64,
709709
val: u8,
710710
len: u64,
711-
) -> Result<(), TrapCode> {
711+
) -> Result<(), Trap> {
712712
let memory = self.get_memory(memory_index);
713713
let dst = self.validate_inbounds(memory.current_length(), dst, len)?;
714714

@@ -738,7 +738,7 @@ impl Instance {
738738
dst: u64,
739739
src: u32,
740740
len: u32,
741-
) -> Result<(), TrapCode> {
741+
) -> Result<(), Trap> {
742742
let range = match self.module().passive_data_map.get(&data_index).cloned() {
743743
Some(range) if !self.dropped_data.contains(data_index) => range,
744744
_ => 0..0,
@@ -757,7 +757,7 @@ impl Instance {
757757
dst: u64,
758758
src: u32,
759759
len: u32,
760-
) -> Result<(), TrapCode> {
760+
) -> Result<(), Trap> {
761761
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init
762762

763763
let memory = self.get_memory(memory_index);

crates/runtime/src/instance/allocator.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::sync::Arc;
1313
use thiserror::Error;
1414
use wasmtime_environ::{
1515
DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
16-
MemoryInitializer, Module, PrimaryMap, TableInitialization, TableInitializer, TrapCode,
17-
VMOffsets, WasmType, WASM_PAGE_SIZE,
16+
MemoryInitializer, Module, PrimaryMap, TableInitialization, TableInitializer, Trap, VMOffsets,
17+
WasmType, WASM_PAGE_SIZE,
1818
};
1919

2020
#[cfg(feature = "pooling-allocator")]
@@ -105,7 +105,7 @@ pub enum InstantiationError {
105105

106106
/// A trap ocurred during instantiation, after linking.
107107
#[error("Trap occurred during instantiation")]
108-
Trap(TrapCode),
108+
Trap(Trap),
109109

110110
/// A limit on how many instances are supported has been reached.
111111
#[error("Limit of {0} concurrent instances has been reached")]
@@ -386,7 +386,7 @@ fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<(), I
386386
},
387387
);
388388
if !ok {
389-
return Err(InstantiationError::Trap(TrapCode::HeapOutOfBounds));
389+
return Err(InstantiationError::Trap(Trap::MemoryOutOfBounds));
390390
}
391391

392392
Ok(())

crates/runtime/src/libcalls.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use anyhow::Result;
6363
use std::mem;
6464
use std::ptr::{self, NonNull};
6565
use wasmtime_environ::{
66-
DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TrapCode,
66+
DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap,
6767
};
6868

6969
/// Actually public trampolines which are used by the runtime as the entrypoint
@@ -228,7 +228,7 @@ unsafe fn table_fill(
228228
// `VMCallerCheckedAnyfunc` until we look at the table's element type.
229229
val: *mut u8,
230230
len: u32,
231-
) -> Result<(), TrapCode> {
231+
) -> Result<(), Trap> {
232232
let instance = (*vmctx).instance_mut();
233233
let table_index = TableIndex::from_u32(table_index);
234234
let table = &mut *instance.get_table(table_index);
@@ -259,7 +259,7 @@ unsafe fn table_copy(
259259
dst: u32,
260260
src: u32,
261261
len: u32,
262-
) -> Result<(), TrapCode> {
262+
) -> Result<(), Trap> {
263263
let dst_table_index = TableIndex::from_u32(dst_table_index);
264264
let src_table_index = TableIndex::from_u32(src_table_index);
265265
let instance = (*vmctx).instance_mut();
@@ -278,7 +278,7 @@ unsafe fn table_init(
278278
dst: u32,
279279
src: u32,
280280
len: u32,
281-
) -> Result<(), TrapCode> {
281+
) -> Result<(), Trap> {
282282
let table_index = TableIndex::from_u32(table_index);
283283
let elem_index = ElemIndex::from_u32(elem_index);
284284
let instance = (*vmctx).instance_mut();
@@ -300,7 +300,7 @@ unsafe fn memory_copy(
300300
src_index: u32,
301301
src: u64,
302302
len: u64,
303-
) -> Result<(), TrapCode> {
303+
) -> Result<(), Trap> {
304304
let src_index = MemoryIndex::from_u32(src_index);
305305
let dst_index = MemoryIndex::from_u32(dst_index);
306306
let instance = (*vmctx).instance_mut();
@@ -314,7 +314,7 @@ unsafe fn memory_fill(
314314
dst: u64,
315315
val: u32,
316316
len: u64,
317-
) -> Result<(), TrapCode> {
317+
) -> Result<(), Trap> {
318318
let memory_index = MemoryIndex::from_u32(memory_index);
319319
let instance = (*vmctx).instance_mut();
320320
instance.memory_fill(memory_index, dst, val as u8, len)
@@ -328,7 +328,7 @@ unsafe fn memory_init(
328328
dst: u64,
329329
src: u32,
330330
len: u32,
331-
) -> Result<(), TrapCode> {
331+
) -> Result<(), Trap> {
332332
let memory_index = MemoryIndex::from_u32(memory_index);
333333
let data_index = DataIndex::from_u32(data_index);
334334
let instance = (*vmctx).instance_mut();
@@ -498,14 +498,14 @@ unsafe fn validate_atomic_addr(
498498
addr: u64,
499499
access_size: u64,
500500
access_alignment: u64,
501-
) -> Result<(), TrapCode> {
501+
) -> Result<(), Trap> {
502502
debug_assert!(access_alignment.is_power_of_two());
503-
ensure!(addr % access_alignment == 0, TrapCode::HeapMisaligned);
503+
ensure!(addr % access_alignment == 0, Trap::HeapMisaligned);
504504

505505
let length = u64::try_from(instance.get_memory(memory).current_length()).unwrap();
506506
ensure!(
507507
addr.saturating_add(access_size) < length,
508-
TrapCode::HeapOutOfBounds
508+
Trap::MemoryOutOfBounds
509509
);
510510

511511
Ok(())

0 commit comments

Comments
 (0)