From 05e6abf2f64820a0f3a7903cfe196f04bffd7832 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 1 Aug 2022 11:03:23 -0500 Subject: [PATCH] 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. --- crates/fuzzing/src/oracles/stacks.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/fuzzing/src/oracles/stacks.rs b/crates/fuzzing/src/oracles/stacks.rs index 3a289a97f9..54dde5801f 100644 --- a/crates/fuzzing/src/oracles/stacks.rs +++ b/crates/fuzzing/src/oracles/stacks.rs @@ -57,7 +57,9 @@ pub fn check_stacks(stacks: Stacks) -> usize { let mut max_stack_depth = 0; for input in stacks.inputs().iter().copied() { + log::debug!("input: {}", input); if let Err(trap) = run.call(&mut store, (input.into(),)) { + log::debug!("trap: {}", trap); let get_stack = instance .get_typed_func::<(), (u32, u32), _>(&mut store, "get_stack") .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(); 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 @@ -85,6 +87,7 @@ fn assert_stack_matches( ptr: u32, len: u32, host_trace: &[FrameInfo], + trap_code: Option, ) { let mut data = vec![0; len as usize]; memory @@ -99,6 +102,19 @@ fn assert_stack_matches( 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!( "Host thinks the stack is: {:?}",