diff --git a/crates/wasmtime/src/runtime/vm/stack_switching.rs b/crates/wasmtime/src/runtime/vm/stack_switching.rs index a96c896ae1ff..5dd2e1bc5c7a 100644 --- a/crates/wasmtime/src/runtime/vm/stack_switching.rs +++ b/crates/wasmtime/src/runtime/vm/stack_switching.rs @@ -410,7 +410,7 @@ pub fn cont_new( /// executing themselves, but are an ancestor of the currently executing /// stack), we have the following: All the fields in the stack's /// `VMStackLimits` are valid, describing the stack's stack limit, and -/// pointers where executing for that stack entered and exited WASM. +/// pointers where executing for that stack entered and exited Wasm. /// /// Suspended continuations: For suspended continuations (including their /// ancestors), we have the following. Note that the initial stack can never diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs index 1f6486bbc64d..95980785c44c 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs @@ -19,6 +19,7 @@ pub use self::signals::*; use crate::ThrownException; use crate::runtime::module::lookup_code; use crate::runtime::store::{ExecutorRef, StoreOpaque}; +use crate::runtime::vm::stack_switching::VMStackChain; use crate::runtime::vm::sys::traphandlers; use crate::runtime::vm::{InterpreterRef, VMContext, VMStore, VMStoreContext, f32x4, f64x2, i8x16}; use crate::{EntryStoreContext, prelude::*}; @@ -866,8 +867,28 @@ impl CallThreadState { pub(crate) fn entry_trap_handler(&self) -> Handler { unsafe { + fn running_on_continuation(stack_chain: *const VMStackChain) -> bool { + unsafe { + match *stack_chain { + VMStackChain::Continuation(_) => true, + _ => false, + } + } + } let vm_store_context = self.vm_store_context.as_ref(); - let fp = *vm_store_context.last_wasm_entry_fp.get(); + let vm_stack_chain = vm_store_context.stack_chain.get(); + // The effects of trapping should not be delimited by the + // continuation stack segment we are running on, but + // rather the initial continuation stack segment, i.e. the + // toplevel part of the program. Therefore we must + // retrieve the entry fp of the initial stack. + let fp = if running_on_continuation(vm_stack_chain) { + let initial_stack_limits = + (*vm_stack_chain).clone().into_stack_limits_iter().last(); + (*initial_stack_limits.unwrap_or_else(|| panic!("Attempting to find the stack limits of the initial stacks from within a suspended continuation."))).last_wasm_entry_fp + } else { + *vm_store_context.last_wasm_entry_fp.get() + }; let sp = *vm_store_context.last_wasm_entry_sp.get(); let pc = *vm_store_context.last_wasm_entry_trap_handler.get(); Handler { pc, sp, fp } diff --git a/tests/misc_testsuite/stack-switching/trap.wast b/tests/misc_testsuite/stack-switching/trap.wast new file mode 100644 index 000000000000..9cc09cf1f479 --- /dev/null +++ b/tests/misc_testsuite/stack-switching/trap.wast @@ -0,0 +1,16 @@ +;;! stack_switching = true +;;! reference_types = true + +(module + (type $ft (func)) + (type $ct (cont $ft)) + + (func $fn + (unreachable)) + + (func $run_fn (export "run_fn") + (resume $ct (cont.new $ct (ref.func $fn)))) + + (elem declare func $fn) +) +(assert_trap (invoke "run_fn") "unreachable") \ No newline at end of file