Skip to content

Commit bf1ece7

Browse files
committed
refactor recursive reentrance checks
This commit makes a few changes related to recursive reentrance checks, instance poisoning, etc.: - Implements the more restrictive lift/lower rules described in WebAssembly/component-model#589 such that a component instance may not lower a function lifted by one of its ancestors, nor vice-versa. Any such lower will result in a fused adapter which traps unconditionally, preventing guest-to-guest recursive reentrance without requiring data flow analysis. - Note that this required updating several WAST tests which were violating the new rule. - This is handled entirely in the `fact` module now; I've removed the `AlwaysTrap` case previously handled by `wasmtime-cranelift`. - Removes `FLAG_MAY_ENTER` from `InstanceFlags`. It is no longer needed for guest-to-guest calls due to the above, and for guest-to-host-to-guest calls we can rely on either `FLAG_NEEDS_POST_RETURN` for sync-lifted functions or the `GuestTask` call stack for async-lifted functions. - Adds a `StoreOpaque::trapped` field which is set when _any_ instance belonging to that store traps, at which point the entire store is considered poisoned, meaning no instance belonging to it may be entered. This prevents indeterminant concurrent task state left over from the trapping instance from leaking into other instances. Note that this does _not_ include code to push and pop `GuestTask` instances for guest-to-guest sync-to-sync calls, nor for host-to-guest calls using e.g. the synchronous `Func::call` API, so certain intrinsics which expect a `GuestTask` to be present such as `backpressure.inc` will still fail in such cases. I'll address that in a later PR. Fixes bytecodealliance#12128
1 parent caf0f75 commit bf1ece7

File tree

36 files changed

+1187
-809
lines changed

36 files changed

+1187
-809
lines changed

crates/cranelift/src/compiler/component.rs

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Compilation support for the component model.
22
3-
use crate::{TRAP_ALWAYS, TRAP_CANNOT_ENTER, TRAP_INTERNAL_ASSERT, compiler::Compiler};
3+
use crate::{TRAP_INTERNAL_ASSERT, compiler::Compiler};
44
use cranelift_codegen::ir::condcodes::IntCC;
55
use cranelift_codegen::ir::{self, InstBuilder, MemFlags, Value};
66
use cranelift_codegen::isa::{CallConv, TargetIsa};
@@ -20,7 +20,6 @@ struct TrampolineCompiler<'a> {
2020
offsets: VMComponentOffsets<u8>,
2121
block0: ir::Block,
2222
signature: &'a WasmFuncType,
23-
tunables: &'a Tunables,
2423
}
2524

2625
/// What host functions can be called, used in `translate_hostcall` below.
@@ -100,7 +99,6 @@ impl<'a> TrampolineCompiler<'a> {
10099
component: &'a Component,
101100
types: &'a ComponentTypesBuilder,
102101
signature: &'a WasmFuncType,
103-
tunables: &'a Tunables,
104102
) -> TrampolineCompiler<'a> {
105103
let isa = &*compiler.isa;
106104
let func = ir::Function::with_name_signature(
@@ -117,7 +115,6 @@ impl<'a> TrampolineCompiler<'a> {
117115
offsets: VMComponentOffsets::new(isa.pointer_bytes(), component),
118116
block0,
119117
signature,
120-
tunables,
121118
}
122119
}
123120

@@ -160,21 +157,6 @@ impl<'a> TrampolineCompiler<'a> {
160157
},
161158
);
162159
}
163-
Trampoline::AlwaysTrap => {
164-
if self.tunables.signals_based_traps {
165-
self.builder.ins().trap(TRAP_ALWAYS);
166-
return;
167-
}
168-
self.translate_libcall(
169-
host::trap,
170-
TrapSentinel::Falsy,
171-
WasmArgs::InRegisters,
172-
|me, params| {
173-
let code = wasmtime_environ::Trap::AlwaysTrapAdapter as u8;
174-
params.push(me.builder.ins().iconst(ir::types::I32, i64::from(code)));
175-
},
176-
);
177-
}
178160
Trampoline::ResourceNew { instance, ty } => {
179161
// Currently this only supports resources represented by `i32`
180162
assert_eq!(self.signature.params()[0], WasmValType::I32);
@@ -1130,13 +1112,8 @@ impl<'a> TrampolineCompiler<'a> {
11301112
// brif should_run_destructor, run_destructor_block, return_block
11311113
//
11321114
// run_destructor_block:
1133-
// ;; test may_enter, but only if the component instances
1134-
// ;; differ
1135-
// flags = load.i32 vmctx+$instance_flags_offset
1136-
// masked = band flags, $FLAG_MAY_ENTER
1137-
// trapz masked, CANNOT_ENTER_CODE
1138-
//
1139-
// ;; set may_block to false, saving the old value to restore later
1115+
// ;; set may_block to false, saving the old value to restore
1116+
// ;; later, but only if the component instances differ
11401117
// old_may_block = load.i32 vmctx+$may_block_offset
11411118
// store 0, vmctx+$may_block_offset
11421119
//
@@ -1184,25 +1161,13 @@ impl<'a> TrampolineCompiler<'a> {
11841161

11851162
self.builder.switch_to_block(run_destructor_block);
11861163

1187-
// If this is a defined resource within the component itself then a
1188-
// check needs to be emitted for the `may_enter` flag. Note though
1189-
// that this check can be elided if the resource table resides in
1190-
// the same component instance that defined the resource as the
1191-
// component is calling itself.
1164+
// If this is a defined resource within the component itself then the
1165+
// `may_block` field must be updated. Note though that this update can
1166+
// be elided if the resource table resides in the same component
1167+
// instance that defined the resource as the component is calling
1168+
// itself.
11921169
let old_may_block = if let Some(def) = resource_def {
11931170
if self.types[resource].unwrap_concrete_instance() != def.instance {
1194-
let flags = self.builder.ins().load(
1195-
ir::types::I32,
1196-
trusted,
1197-
vmctx,
1198-
i32::try_from(self.offsets.instance_flags(def.instance)).unwrap(),
1199-
);
1200-
let masked = self
1201-
.builder
1202-
.ins()
1203-
.band_imm(flags, i64::from(FLAG_MAY_ENTER));
1204-
self.builder.ins().trapz(masked, TRAP_CANNOT_ENTER);
1205-
12061171
// Stash the old value of `may_block` and then set it to false.
12071172
let old_may_block = self.builder.ins().load(
12081173
ir::types::I32,
@@ -1434,7 +1399,7 @@ impl ComponentCompiler for Compiler {
14341399
types: &ComponentTypesBuilder,
14351400
key: FuncKey,
14361401
abi: Abi,
1437-
tunables: &Tunables,
1402+
_tunables: &Tunables,
14381403
symbol: &str,
14391404
) -> Result<CompiledFunctionBody> {
14401405
let (abi2, trampoline_index) = key.unwrap_component_trampoline();
@@ -1466,14 +1431,7 @@ impl ComponentCompiler for Compiler {
14661431
}
14671432

14681433
let mut compiler = self.function_compiler();
1469-
let mut c = TrampolineCompiler::new(
1470-
self,
1471-
&mut compiler,
1472-
&component.component,
1473-
types,
1474-
sig,
1475-
tunables,
1476-
);
1434+
let mut c = TrampolineCompiler::new(self, &mut compiler, &component.component, types, sig);
14771435

14781436
// If we are crossing the Wasm-to-native boundary, we need to save the
14791437
// exit FP and return address for stack walking purposes. However, we
@@ -1512,7 +1470,7 @@ impl ComponentCompiler for Compiler {
15121470

15131471
fn compile_intrinsic(
15141472
&self,
1515-
tunables: &Tunables,
1473+
_tunables: &Tunables,
15161474
component: &ComponentTranslation,
15171475
types: &ComponentTypesBuilder,
15181476
intrinsic: UnsafeIntrinsic,
@@ -1557,7 +1515,6 @@ impl ComponentCompiler for Compiler {
15571515
&component.component,
15581516
&types,
15591517
&wasm_func_ty,
1560-
tunables,
15611518
);
15621519

15631520
match intrinsic {

crates/cranelift/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@ use self::compiler::Compiler;
4848

4949
const TRAP_INTERNAL_ASSERT: TrapCode = TrapCode::unwrap_user(1);
5050
const TRAP_OFFSET: u8 = 2;
51-
pub const TRAP_ALWAYS: TrapCode =
52-
TrapCode::unwrap_user(Trap::AlwaysTrapAdapter as u8 + TRAP_OFFSET);
53-
pub const TRAP_CANNOT_ENTER: TrapCode =
54-
TrapCode::unwrap_user(Trap::CannotEnterComponent as u8 + TRAP_OFFSET);
5551
pub const TRAP_INDIRECT_CALL_TO_NULL: TrapCode =
5652
TrapCode::unwrap_user(Trap::IndirectCallToNull as u8 + TRAP_OFFSET);
5753
pub const TRAP_BAD_SIGNATURE: TrapCode =

crates/environ/src/component/dfg.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,6 @@ pub enum Trampoline {
326326
to: MemoryId,
327327
to64: bool,
328328
},
329-
AlwaysTrap,
330329
ResourceNew {
331330
instance: RuntimeComponentInstanceIndex,
332331
ty: TypeResourceTableIndex,
@@ -945,7 +944,6 @@ impl LinearizeDfg<'_> {
945944
to: self.runtime_memory(*to),
946945
to64: *to64,
947946
},
948-
Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
949947
Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {
950948
instance: *instance,
951949
ty: *ty,

crates/environ/src/component/info.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,6 @@ pub enum Trampoline {
734734
to64: bool,
735735
},
736736

737-
/// A small adapter which simply traps, used for degenerate lift/lower
738-
/// combinations.
739-
AlwaysTrap,
740-
741737
/// A `resource.new` intrinsic which will inject a new resource into the
742738
/// table specified.
743739
ResourceNew {
@@ -1199,7 +1195,6 @@ impl Trampoline {
11991195
let to = if *to64 { "64" } else { "32" };
12001196
format!("component-transcode-{op}-m{from}-m{to}")
12011197
}
1202-
AlwaysTrap => format!("component-always-trap"),
12031198
ResourceNew { ty, .. } => format!("component-resource-new[{}]", ty.as_u32()),
12041199
ResourceRep { ty, .. } => format!("component-resource-rep[{}]", ty.as_u32()),
12051200
ResourceDrop { ty, .. } => format!("component-resource-drop[{}]", ty.as_u32()),

crates/environ/src/component/translate/adapt.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ pub struct AdapterOptions {
166166
/// The Wasmtime-assigned component instance index where the options were
167167
/// originally specified.
168168
pub instance: RuntimeComponentInstanceIndex,
169+
/// The ancestors (i.e. chain of instantiating instances) of the instance
170+
/// specified in the `instance` field.
171+
pub ancestors: Vec<RuntimeComponentInstanceIndex>,
169172
/// How strings are encoded.
170173
pub string_encoding: StringEncoding,
171174
/// The async callback function used by these options, if specified.

0 commit comments

Comments
 (0)