Skip to content

Commit c99bf94

Browse files
authored
Debugging: set vmctx slot before top-of-function epoch yield point. (#12664)
Epoch yields emit debug events, and the debug event handler can walk the stack and look at the instance associated with each frame, which requires `vmctx`. We weren't setting the `vmctx` slot until after the epoch check in the function preamble, exposing a null or uninitialized slot to the accessor. This PR fixes that by hoisting the initialization to the very top of the preamble.
1 parent f85e4d0 commit c99bf94

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

crates/cranelift/src/func_environ.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3865,6 +3865,8 @@ impl FuncEnvironment<'_> {
38653865
self.conditionally_trap(builder, overflow, ir::TrapCode::STACK_OVERFLOW);
38663866
}
38673867

3868+
self.update_state_slot_vmctx(builder);
3869+
38683870
// Additionally we initialize `fuel_var` if it will get used.
38693871
if self.tunables.consume_fuel {
38703872
self.fuel_function_entry(builder);
@@ -3885,8 +3887,6 @@ impl FuncEnvironment<'_> {
38853887
}
38863888
}
38873889

3888-
self.update_state_slot_vmctx(builder);
3889-
38903890
Ok(())
38913891
}
38923892

tests/all/debug.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,3 +1372,51 @@ async fn single_step_before_instantiation() -> wasmtime::Result<()> {
13721372

13731373
Ok(())
13741374
}
1375+
1376+
#[tokio::test]
1377+
#[cfg_attr(miri, ignore)]
1378+
async fn early_epoch_yield_still_has_vmctx() -> wasmtime::Result<()> {
1379+
let _ = env_logger::try_init();
1380+
1381+
let mut config = Config::default();
1382+
config.guest_debug(true);
1383+
config.epoch_interruption(true);
1384+
let engine = Engine::new(&config)?;
1385+
let module = Module::new(
1386+
&engine,
1387+
r#"
1388+
(module
1389+
(func (export "main") (param i32 i32) (result i32)
1390+
local.get 0
1391+
local.get 1
1392+
i32.add))
1393+
"#,
1394+
)?;
1395+
let mut store = Store::new(&engine, ());
1396+
store.set_epoch_deadline(1);
1397+
store.epoch_deadline_async_yield_and_update(1);
1398+
engine.increment_epoch();
1399+
1400+
#[derive(Clone)]
1401+
struct H;
1402+
impl DebugHandler for H {
1403+
type Data = ();
1404+
async fn handle(&self, mut store: StoreContextMut<'_, ()>, _event: DebugEvent<'_>) {
1405+
// Ensure we can access the instance (which accesses the
1406+
// vmctx slot in the frame's debug info).
1407+
let frame = store.debug_exit_frames().next().unwrap();
1408+
let _instance = frame.instance(&mut store);
1409+
}
1410+
}
1411+
1412+
store.set_debug_handler(H);
1413+
1414+
let instance = Instance::new_async(&mut store, &module, &[]).await?;
1415+
let func = instance.get_func(&mut store, "main").unwrap();
1416+
let mut results = [Val::I32(0)];
1417+
func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
1418+
.await?;
1419+
assert_eq!(results[0].unwrap_i32(), 3);
1420+
1421+
Ok(())
1422+
}

0 commit comments

Comments
 (0)