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.
This commit is contained in:
Alex Crichton
2022-08-01 11:03:23 -05:00
committed by GitHub
parent 04631ad0af
commit 05e6abf2f6

View File

@@ -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: {:?}",