Skip to content

Commit

Permalink
[27.0.0] winch: Sync registers and locals before fuel check (#9564)
Browse files Browse the repository at this point in the history
* winch: Sync registers and locals before fuel check

This commit fixes a fuzz bug in which the stack was misaligned when
calling the out-of-fuel builtin function.

The misalignment was introduced by a erroneous handling of the the
control flow merge introduced by the fuel check conditional. In general,
prior to every branch emission, a spill to memory is needed to avoid
issues at the control flow merge.

Note that we don't have many cases like this one in Winch's codebase (3
in total), however as a follow-up, it's probably worth considering
introducing a stronger abstraction around branching to ensure that this
case is handled whenever an arbitrary branch needs to be introduced.
This change solely focuses on the fix and does not introduce any
refactoring. I plan to follow-up with investigating a better branching
strategy, since we would need to introduce a similar pattern for epoch
handling.

I used `wasm-tools shink` to shrink the original program, which
I decided to add as part of an integration test.

* Move the test fixture
  • Loading branch information
saulecabrera authored Nov 5, 2024
1 parent 490ea33 commit 46b744d
Show file tree
Hide file tree
Showing 3 changed files with 404 additions and 0 deletions.
20 changes: 20 additions & 0 deletions tests/all/fuel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,23 @@ fn get_fuel_clamps_at_zero(config: &mut Config) -> Result<()> {

Ok(())
}

#[wasmtime_test(strategies(not(Cranelift)))]
#[cfg_attr(miri, ignore)]
fn ensure_stack_alignment(config: &mut Config) -> Result<()> {
config.consume_fuel(true);
let engine = Engine::new(config)?;
let mut store = Store::new(&engine, ());
store.set_fuel(100000000)?;

let bytes = include_bytes!("../misc_testsuite/winch/fuel_stack_alignment.wat");
let module = Module::new(&engine, bytes)?;
let instance = Instance::new(&mut store, &module, &[])?;
let func = instance.get_typed_func::<f32, ()>(&mut store, "")?;
let trap = func.call(&mut store, 50397184.0).unwrap_err();
assert_eq!(
trap.downcast::<Trap>().unwrap(),
Trap::UnreachableCodeReached
);
Ok(())
}
Loading

0 comments on commit 46b744d

Please sign in to comment.