Skip to content

Commit ee7e125

Browse files
authored
Respect signals-based-traps in component trampolines (#12626)
This commit fixes a regression from #12547 where traps happening in component trampolines weren't respecting the signals-based-traps configuration of the `Engine` meaning that native CLIF traps could be executed in environments which weren't configured to catch it. This refactors the implementation internally to share more code with `FuncEnvironment` through some traits to ensure that the same knobs and plumbing are used to translate traps.
1 parent d54924a commit ee7e125

12 files changed

Lines changed: 281 additions & 128 deletions

File tree

crates/cranelift/src/bounds_checks.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::{
2323
Reachability,
2424
func_environ::FuncEnvironment,
2525
translate::{HeapData, TargetEnvironment},
26+
trap::TranslateTrap,
2627
};
2728
use Reachability::*;
2829
use cranelift_codegen::{

crates/cranelift/src/compiler/component.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
//! Compilation support for the component model.
22
3+
use crate::func_environ::BuiltinFunctions;
4+
use crate::trap::TranslateTrap;
35
use crate::{TRAP_CANNOT_LEAVE_COMPONENT, TRAP_INTERNAL_ASSERT, compiler::Compiler};
6+
use cranelift_codegen::cursor::FuncCursor;
47
use cranelift_codegen::ir::condcodes::IntCC;
58
use cranelift_codegen::ir::{self, InstBuilder, MemFlags, Value};
69
use cranelift_codegen::isa::{CallConv, TargetIsa};
710
use cranelift_frontend::FunctionBuilder;
811
use wasmtime_environ::error::{Result, bail};
912
use wasmtime_environ::{
10-
Abi, CompiledFunctionBody, EntityRef, FuncKey, HostCall, PtrSize, TrapSentinel, Tunables,
11-
WasmFuncType, WasmValType, component::*, fact::PREPARE_CALL_FIXED_PARAMS,
13+
Abi, BuiltinFunctionIndex, CompiledFunctionBody, EntityRef, FuncKey, HostCall, PtrSize,
14+
TrapSentinel, Tunables, WasmFuncType, WasmValType, component::*,
15+
fact::PREPARE_CALL_FIXED_PARAMS,
1216
};
1317

1418
struct TrampolineCompiler<'a> {
@@ -20,6 +24,7 @@ struct TrampolineCompiler<'a> {
2024
offsets: VMComponentOffsets<u8>,
2125
block0: ir::Block,
2226
signature: &'a WasmFuncType,
27+
builtins: BuiltinFunctions,
2328
}
2429

2530
/// What host functions can be called, used in `translate_hostcall` below.
@@ -112,6 +117,7 @@ impl<'a> TrampolineCompiler<'a> {
112117
offsets: VMComponentOffsets::new(isa.pointer_bytes(), component),
113118
block0,
114119
signature,
120+
builtins: BuiltinFunctions::new(compiler),
115121
}
116122
}
117123

@@ -1412,8 +1418,12 @@ impl<'a> TrampolineCompiler<'a> {
14121418
self.builder.ins().return_(results);
14131419
}
14141420

1421+
fn caller_vmctx(&self) -> ir::Value {
1422+
self.builder.func.dfg.block_params(self.block0)[1]
1423+
}
1424+
14151425
fn raise_if_host_trapped(&mut self, succeeded: ir::Value) {
1416-
let caller_vmctx = self.builder.func.dfg.block_params(self.block0)[1];
1426+
let caller_vmctx = self.caller_vmctx();
14171427
self.compiler
14181428
.raise_if_host_trapped(&mut self.builder, caller_vmctx, succeeded);
14191429
}
@@ -1533,9 +1543,45 @@ impl<'a> TrampolineCompiler<'a> {
15331543
.builder
15341544
.ins()
15351545
.band_imm(flags, i64::from(FLAG_MAY_LEAVE));
1536-
self.builder
1537-
.ins()
1538-
.trapz(may_leave_bit, TRAP_CANNOT_LEAVE_COMPONENT);
1546+
let (mut traps, builder) = self.traps();
1547+
traps.trapz(builder, may_leave_bit, TRAP_CANNOT_LEAVE_COMPONENT);
1548+
}
1549+
1550+
fn traps(&mut self) -> (TrapTranslator<'_>, &mut FunctionBuilder<'a>) {
1551+
(
1552+
TrapTranslator {
1553+
compiler: self.compiler,
1554+
vmctx: self.builder.func.dfg.block_params(self.block0)[0],
1555+
builtins: &mut self.builtins,
1556+
},
1557+
&mut self.builder,
1558+
)
1559+
}
1560+
}
1561+
1562+
// Helper structure to implement `TranslateTrap`. This isn't possible to do
1563+
// natively for `TrampolineCompiler` because it stores `FunctionBuilder`
1564+
// internally. This differs from `FuncEnvironment` for core wasm which stores it
1565+
// externally, hence the slightly different idioms to bridge here.
1566+
struct TrapTranslator<'a> {
1567+
compiler: &'a Compiler,
1568+
vmctx: ir::Value,
1569+
builtins: &'a mut BuiltinFunctions,
1570+
}
1571+
1572+
impl TranslateTrap for TrapTranslator<'_> {
1573+
fn compiler(&self) -> &Compiler {
1574+
self.compiler
1575+
}
1576+
fn vmctx_val(&mut self, _: &mut FuncCursor<'_>) -> ir::Value {
1577+
self.vmctx
1578+
}
1579+
fn builtin_funcref(
1580+
&mut self,
1581+
builder: &mut FunctionBuilder<'_>,
1582+
index: BuiltinFunctionIndex,
1583+
) -> ir::FuncRef {
1584+
self.builtins.load_builtin(builder.func, index)
15391585
}
15401586
}
15411587

crates/cranelift/src/func_environ.rs

Lines changed: 31 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
mod gc;
22
pub(crate) mod stack_switching;
33

4+
use crate::BuiltinFunctionSignatures;
45
use crate::compiler::Compiler;
56
use crate::translate::{
67
FuncTranslationStacks, GlobalVariable, Heap, HeapData, StructFieldsVec, TableData, TableSize,
78
TargetEnvironment,
89
};
9-
use crate::{BuiltinFunctionSignatures, TRAP_INTERNAL_ASSERT};
10+
use crate::trap::TranslateTrap;
1011
use cranelift_codegen::cursor::FuncCursor;
1112
use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
1213
use cranelift_codegen::ir::immediates::{Imm64, Offset32, V128Imm};
@@ -29,9 +30,9 @@ use wasmtime_environ::{
2930
BuiltinFunctionIndex, DataIndex, DefinedFuncIndex, ElemIndex, EngineOrModuleTypeIndex,
3031
FrameStateSlotBuilder, FrameValType, FuncIndex, FuncKey, GlobalConstValue, GlobalIndex,
3132
IndexType, Memory, MemoryIndex, Module, ModuleInternedTypeIndex, ModuleTranslation,
32-
ModuleTypesBuilder, PtrSize, Table, TableIndex, TagIndex, TripleExt, Tunables, TypeConvert,
33-
TypeIndex, VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType,
34-
WasmRefType, WasmResult, WasmValType,
33+
ModuleTypesBuilder, PtrSize, Table, TableIndex, TagIndex, Tunables, TypeConvert, TypeIndex,
34+
VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType, WasmRefType,
35+
WasmResult, WasmValType,
3536
};
3637
use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK};
3738

@@ -51,15 +52,19 @@ pub(crate) struct BuiltinFunctions {
5152
}
5253

5354
impl BuiltinFunctions {
54-
fn new(compiler: &Compiler) -> Self {
55+
pub(crate) fn new(compiler: &Compiler) -> Self {
5556
Self {
5657
types: BuiltinFunctionSignatures::new(compiler),
5758
builtins: [None; BuiltinFunctionIndex::len() as usize],
5859
breakpoint_trampoline: None,
5960
}
6061
}
6162

62-
fn load_builtin(&mut self, func: &mut Function, builtin: BuiltinFunctionIndex) -> ir::FuncRef {
63+
pub(crate) fn load_builtin(
64+
&mut self,
65+
func: &mut Function,
66+
builtin: BuiltinFunctionIndex,
67+
) -> ir::FuncRef {
6368
let cache = &mut self.builtins[builtin.index() as usize];
6469
if let Some(f) = cache {
6570
return *f;
@@ -312,12 +317,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
312317
})
313318
}
314319

315-
pub(crate) fn vmctx_val(&mut self, pos: &mut FuncCursor<'_>) -> ir::Value {
316-
let pointer_type = self.pointer_type();
317-
let vmctx = self.vmctx(&mut pos.func);
318-
pos.ins().global_value(pointer_type, vmctx)
319-
}
320-
321320
fn get_table_copy_func(
322321
&mut self,
323322
func: &mut Function,
@@ -1034,34 +1033,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
10341033
self.global_load_with_memory_type(func, vmctx, offset, flags, self.pcc_vmctx_memtype)
10351034
}
10361035

1037-
/// Helper to emit a conditional trap based on `trap_cond`.
1038-
///
1039-
/// This should only be used if `self.clif_instruction_traps_enabled()` is
1040-
/// false, otherwise native CLIF instructions should be used instead.
1041-
pub fn conditionally_trap(
1042-
&mut self,
1043-
builder: &mut FunctionBuilder,
1044-
trap_cond: ir::Value,
1045-
trap: ir::TrapCode,
1046-
) {
1047-
assert!(!self.clif_instruction_traps_enabled());
1048-
1049-
let trap_block = builder.create_block();
1050-
builder.set_cold_block(trap_block);
1051-
let continuation_block = builder.create_block();
1052-
1053-
builder
1054-
.ins()
1055-
.brif(trap_cond, trap_block, &[], continuation_block, &[]);
1056-
1057-
builder.seal_block(trap_block);
1058-
builder.seal_block(continuation_block);
1059-
1060-
builder.switch_to_block(trap_block);
1061-
self.trap(builder, trap);
1062-
builder.switch_to_block(continuation_block);
1063-
}
1064-
10651036
/// Helper used when `!self.clif_instruction_traps_enabled()` is enabled to
10661037
/// test whether the divisor is zero.
10671038
fn guard_zero_divisor(&mut self, builder: &mut FunctionBuilder, rhs: ir::Value) {
@@ -1395,6 +1366,26 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
13951366
}
13961367
}
13971368

1369+
impl TranslateTrap for FuncEnvironment<'_> {
1370+
fn compiler(&self) -> &Compiler {
1371+
&self.compiler
1372+
}
1373+
1374+
fn vmctx_val(&mut self, pos: &mut FuncCursor<'_>) -> ir::Value {
1375+
let pointer_type = self.pointer_type();
1376+
let vmctx = self.vmctx(&mut pos.func);
1377+
pos.ins().global_value(pointer_type, vmctx)
1378+
}
1379+
1380+
fn builtin_funcref(
1381+
&mut self,
1382+
builder: &mut FunctionBuilder<'_>,
1383+
index: BuiltinFunctionIndex,
1384+
) -> ir::FuncRef {
1385+
self.builtin_functions.load_builtin(builder.func, index)
1386+
}
1387+
}
1388+
13981389
#[derive(Default)]
13991390
pub(crate) struct WasmEntities {
14001391
/// Map from a Wasm global index from this module to its implementation in
@@ -4431,70 +4422,6 @@ impl FuncEnvironment<'_> {
44314422
&*self.isa
44324423
}
44334424

4434-
pub fn trap(&mut self, builder: &mut FunctionBuilder, trap: ir::TrapCode) {
4435-
match (
4436-
self.clif_instruction_traps_enabled(),
4437-
crate::clif_trap_to_env_trap(trap),
4438-
) {
4439-
// If libcall traps are disabled or there's no wasmtime-defined trap
4440-
// code for this, then emit a native trap instruction.
4441-
(true, _) | (_, None) => {
4442-
builder.ins().trap(trap);
4443-
}
4444-
// ... otherwise with libcall traps explicitly enabled and a
4445-
// wasmtime-based trap code invoke the libcall to raise a trap and
4446-
// pass in our trap code. Leave a debug `unreachable` in place
4447-
// afterwards as a defense-in-depth measure.
4448-
(false, Some(trap)) => {
4449-
let libcall = self.builtin_functions.trap(&mut builder.func);
4450-
let vmctx = self.vmctx_val(&mut builder.cursor());
4451-
let trap_code = builder.ins().iconst(I8, i64::from(trap as u8));
4452-
builder.ins().call(libcall, &[vmctx, trap_code]);
4453-
let raise = self.builtin_functions.raise(&mut builder.func);
4454-
builder.ins().call(raise, &[vmctx]);
4455-
builder.ins().trap(TRAP_INTERNAL_ASSERT);
4456-
}
4457-
}
4458-
}
4459-
4460-
pub fn trapz(&mut self, builder: &mut FunctionBuilder, value: ir::Value, trap: ir::TrapCode) {
4461-
if self.clif_instruction_traps_enabled() {
4462-
builder.ins().trapz(value, trap);
4463-
} else {
4464-
let ty = builder.func.dfg.value_type(value);
4465-
let zero = builder.ins().iconst(ty, 0);
4466-
let cmp = builder.ins().icmp(IntCC::Equal, value, zero);
4467-
self.conditionally_trap(builder, cmp, trap);
4468-
}
4469-
}
4470-
4471-
pub fn trapnz(&mut self, builder: &mut FunctionBuilder, value: ir::Value, trap: ir::TrapCode) {
4472-
if self.clif_instruction_traps_enabled() {
4473-
builder.ins().trapnz(value, trap);
4474-
} else {
4475-
let ty = builder.func.dfg.value_type(value);
4476-
let zero = builder.ins().iconst(ty, 0);
4477-
let cmp = builder.ins().icmp(IntCC::NotEqual, value, zero);
4478-
self.conditionally_trap(builder, cmp, trap);
4479-
}
4480-
}
4481-
4482-
pub fn uadd_overflow_trap(
4483-
&mut self,
4484-
builder: &mut FunctionBuilder,
4485-
lhs: ir::Value,
4486-
rhs: ir::Value,
4487-
trap: ir::TrapCode,
4488-
) -> ir::Value {
4489-
if self.clif_instruction_traps_enabled() {
4490-
builder.ins().uadd_overflow_trap(lhs, rhs, trap)
4491-
} else {
4492-
let (ret, overflow) = builder.ins().uadd_overflow(lhs, rhs);
4493-
self.conditionally_trap(builder, overflow, trap);
4494-
ret
4495-
}
4496-
}
4497-
44984425
pub fn translate_sdiv(
44994426
&mut self,
45004427
builder: &mut FunctionBuilder,
@@ -4572,19 +4499,6 @@ impl FuncEnvironment<'_> {
45724499
self.tunables.signals_based_traps && !self.is_pulley()
45734500
}
45744501

4575-
/// Returns whether it's acceptable to have CLIF instructions natively trap,
4576-
/// such as division-by-zero.
4577-
///
4578-
/// This is enabled if `signals_based_traps` is `true` or on
4579-
/// Pulley unconditionally since Pulley doesn't use hardware-based
4580-
/// traps in its runtime. However, if guest debugging is enabled,
4581-
/// then we cannot rely on Pulley traps and still need a libcall
4582-
/// to gain proper ownership of the store in the runtime's
4583-
/// debugger hooks.
4584-
pub fn clif_instruction_traps_enabled(&self) -> bool {
4585-
self.tunables.signals_based_traps || (self.is_pulley() && !self.tunables.debug_guest)
4586-
}
4587-
45884502
/// Returns whether loads from the null address are allowed as signals of
45894503
/// whether to trap or not.
45904504
pub fn load_from_zero_allowed(&self) -> bool {
@@ -4594,11 +4508,6 @@ impl FuncEnvironment<'_> {
45944508
|| (self.clif_memory_traps_enabled() && self.heap_access_spectre_mitigation())
45954509
}
45964510

4597-
/// Returns whether translation is happening for Pulley bytecode.
4598-
pub fn is_pulley(&self) -> bool {
4599-
self.isa.triple().is_pulley()
4600-
}
4601-
46024511
/// Returns whether the current location is reachable.
46034512
pub fn is_reachable(&self) -> bool {
46044513
self.stacks.reachable()

crates/cranelift/src/func_environ/gc/enabled.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::{ArrayInit, GcCompiler};
22
use crate::bounds_checks::BoundsCheck;
33
use crate::func_environ::{Extension, FuncEnvironment};
44
use crate::translate::{Heap, HeapData, StructFieldsVec, TargetEnvironment};
5+
use crate::trap::TranslateTrap;
56
use crate::{Reachability, TRAP_INTERNAL_ASSERT};
67
use cranelift_codegen::ir::immediates::Offset32;
78
use cranelift_codegen::ir::{BlockArg, ExceptionTableData, ExceptionTableItem};

crates/cranelift/src/func_environ/gc/enabled/drc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use super::*;
55
use crate::translate::TargetEnvironment;
6+
use crate::trap::TranslateTrap;
67
use crate::{TRAP_INTERNAL_ASSERT, func_environ::FuncEnvironment};
78
use cranelift_codegen::ir::condcodes::IntCC;
89
use cranelift_codegen::ir::{self, InstBuilder};

crates/cranelift/src/func_environ/gc/enabled/null.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
use super::*;
88
use crate::func_environ::FuncEnvironment;
9+
use crate::trap::TranslateTrap;
910
use cranelift_codegen::ir::{self, InstBuilder};
1011
use cranelift_frontend::FunctionBuilder;
1112
use wasmtime_environ::VMSharedTypeIndex;

crates/cranelift/src/func_environ/stack_switching/instructions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use cranelift_codegen::ir::BlockArg;
22
use itertools::{Either, Itertools};
33

4+
use crate::trap::TranslateTrap;
45
use cranelift_codegen::ir::condcodes::*;
56
use cranelift_codegen::ir::types::*;
67
use cranelift_codegen::ir::{self, MemFlags};

crates/cranelift/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ mod compiler;
4343
mod debug;
4444
mod func_environ;
4545
mod translate;
46+
mod trap;
4647

4748
use self::compiler::Compiler;
4849

crates/cranelift/src/translate/code_translator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ use crate::translate::stack::{ControlStackFrame, ElseData};
8080
use crate::translate::translation_utils::{
8181
block_with_params, blocktype_params_results, f32_translation, f64_translation,
8282
};
83+
use crate::trap::TranslateTrap;
8384
use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
8485
use cranelift_codegen::ir::immediates::Offset32;
8586
use cranelift_codegen::ir::{

crates/cranelift/src/translate/table.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::func_environ::FuncEnvironment;
2+
use crate::trap::TranslateTrap;
23
use cranelift_codegen::cursor::FuncCursor;
34
use cranelift_codegen::ir::{self, InstBuilder, condcodes::IntCC, immediates::Imm64};
45
use cranelift_codegen::isa::TargetIsa;

0 commit comments

Comments
 (0)