Browse Source

Fix the `stacks` fuzzer in the face of stack overflow (#4557)

When the `stacks` fuzzer hits a stack overflow the trace generated by
Wasmtime will have one more frame than the trace generated by the wasm
itself. This comes about due to the wasm not actually pushing the final
frame when it stack overflows. The host, however, will still see the
final frame that triggered the stack overflow.

In this situation the fuzzer asserts that the host has one extra frame
and then discards the frame.
pull/4572/head
Alex Crichton 2 years ago
committed by GitHub
parent
commit
05e6abf2f6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      crates/fuzzing/src/oracles/stacks.rs

18
crates/fuzzing/src/oracles/stacks.rs

@ -57,7 +57,9 @@ pub fn check_stacks(stacks: Stacks) -> usize {
let mut max_stack_depth = 0; let mut max_stack_depth = 0;
for input in stacks.inputs().iter().copied() { for input in stacks.inputs().iter().copied() {
log::debug!("input: {}", input);
if let Err(trap) = run.call(&mut store, (input.into(),)) { if let Err(trap) = run.call(&mut store, (input.into(),)) {
log::debug!("trap: {}", trap);
let get_stack = instance let get_stack = instance
.get_typed_func::<(), (u32, u32), _>(&mut store, "get_stack") .get_typed_func::<(), (u32, u32), _>(&mut store, "get_stack")
.expect("should export `get_stack` function as expected"); .expect("should export `get_stack` function as expected");
@ -72,7 +74,7 @@ pub fn check_stacks(stacks: Stacks) -> usize {
let host_trace = trap.trace().unwrap(); let host_trace = trap.trace().unwrap();
max_stack_depth = max_stack_depth.max(host_trace.len()); max_stack_depth = max_stack_depth.max(host_trace.len());
assert_stack_matches(&mut store, memory, ptr, len, host_trace); assert_stack_matches(&mut store, memory, ptr, len, host_trace, trap.trap_code());
} }
} }
max_stack_depth max_stack_depth
@ -85,6 +87,7 @@ fn assert_stack_matches(
ptr: u32, ptr: u32,
len: u32, len: u32,
host_trace: &[FrameInfo], host_trace: &[FrameInfo],
trap_code: Option<TrapCode>,
) { ) {
let mut data = vec![0; len as usize]; let mut data = vec![0; len as usize];
memory memory
@ -99,6 +102,19 @@ fn assert_stack_matches(
wasm_trace.push(entry); wasm_trace.push(entry);
} }
// If the test case here trapped due to stack overflow then the host trace
// will have one more frame than the wasm trace. The wasm didn't actually
// get to the point of pushing onto its own trace stack where the host will
// be able to see the exact function that triggered the stack overflow. In
// this situation the host trace is asserted to be one larger and then the
// top frame (first) of the host trace is discarded.
let host_trace = if trap_code == Some(TrapCode::StackOverflow) {
assert_eq!(host_trace.len(), wasm_trace.len() + 1);
&host_trace[1..]
} else {
host_trace
};
log::debug!("Wasm thinks its stack is: {:?}", wasm_trace); log::debug!("Wasm thinks its stack is: {:?}", wasm_trace);
log::debug!( log::debug!(
"Host thinks the stack is: {:?}", "Host thinks the stack is: {:?}",

Loading…
Cancel
Save