vouillon opened issue #11489:
Test Case
Steps to Reproduce
Run the following command:
./target/debug/wasmtime -W=all-proposals=y bug.wasmExpected Results
It should not crash
Actual Results
I get a segfault
Versions and Environment
Wasmtime commit: 2d25f862b38abd484e5418327a9149e69d3274aa
Operating system: Linux
Architecture: x64
Extra Info
I suspect that the stack unwinder does not deal properly with tail calls.
I get the following stack trace in gdb:
#0 wasmtime::runtime::vm::ModuleRuntimeInfo::env_module (self=0x7ffeffffff68) at crates/wasmtime/src/runtime/vm.rs:329 #1 0x0000555557fd524f in wasmtime::runtime::vm::instance::Instance::env_module (self=0x7ffeffffff60) at crates/wasmtime/src/runtime/vm/instance.rs:357 #2 0x0000555557fd5fe8 in wasmtime::runtime::vm::instance::Instance::get_exported_tag (self=0x7ffeffffff60, store=..., index=...) at crates/wasmtime/src/runtime/vm/instance.rs:666 #3 0x0000555557fb4cad in wasmtime::runtime::vm::throw::compute_throw_action::{closure#0} (frame=0x7ffff69f48f0) at crates/wasmtime/src/runtime/vm/throw.rs:98 #4 0x0000555557f12e5e in wasmtime_internal_unwinder::throw::compute_throw_action::{closure#0}<wasmtime::runtime::vm::throw::compute_throw_action::{closure_env#0}> (frame=...) at crates/unwinder/src/throw.rs:76 #5 0x0000555558034d24 in wasmtime_internal_unwinder::stackwalk::visit_frames<wasmtime_internal_unwinder::throw::ThrowAction, wasmtime_internal_unwinder::throw::compute_throw_action::{closure_env#0}<wasmtime::runtime::vm::throw::compute_throw_action::{closure_env#0}>> (unwind=..., pc=140737353797698, fp=140737331026544, trampoline_fp=140737331026560, f=...) at crates/unwinder/src/stackwalk.rs:203 #6 0x0000555557f12c31 in wasmtime_internal_unwinder::throw::compute_throw_action<wasmtime::runtime::vm::throw::compute_throw_action::{closure_env#0}> ( unwind=..., frame_handler=..., exit_pc=140737353797991, exit_trampoline_frame=140737331026368, entry_frame=140737331026560) at crates/unwinder/src/throw.rs:60 --Type <RET> for more, q to quit, c to continue without paging-- #7 0x0000555557da8980 in wasmtime::runtime::vm::throw::compute_throw_action ( store=...) at crates/wasmtime/src/runtime/vm/throw.rs:120 #8 0x0000555557be3f0a in wasmtime::runtime::vm::traphandlers::call_thread_state::CallThreadState::record_unwind (self=0x7ffff69f5f30, store=..., reason=...) at crates/wasmtime/src/runtime/vm/traphandlers.rs:819 #9 0x0000555558088a8b in wasmtime::runtime::vm::traphandlers::catch_unwind_and_record_trap::{closure#1}<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::instance::{impl#0}::enter_host_from_wasm::{closure_env#0}<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::libcalls::raw::throw_ref::{closure_env#0}>> (info=...) at crates/wasmtime/src/runtime/vm/traphandlers.rs:136 #10 0x0000555557eff1ef in wasmtime::runtime::vm::traphandlers::tls::with<(), wasmtime::runtime::vm::traphandlers::catch_unwind_and_record_trap::{closure_env#1}<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::instance::{impl#0}::enter_host_from_wasm::{closure_env#0}<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::libcalls::raw::throw_ref::{closure_env#0}>>> (closure=...) at crates/wasmtime/src/runtime/vm/traphandlers.rs:1394 #11 0x0000555558084079 in wasmtime::runtime::vm::traphandlers::catch_unwind_and_record_trap<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::instance::{impl#0}::enter_host_from_wasm::{closure_env#0}<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::libcalls::raw::throw_ref::{closure_env#0}>> ( store=..., f=...) at crates/wasmtime/src/runtime/vm/traphandlers.rs:136 #12 0x0000555557c650b2 in wasmtime::runtime::vm::instance::Instance::enter_host_from_wasm<core::result::Result<(), wasmtime::runtime::vm::traphandlers::TrapReason>, wasmtime::runtime::vm::libcalls::raw::throw_ref::{closure_env#0}> ( vmctx=..., f=...) at crates/wasmtime/src/runtime/vm/instance.rs:265 #13 0x0000555557f6b0bb in wasmtime::runtime::vm::libcalls::raw::throw_ref ( vmctx=..., exnref=16) at crates/wasmtime/src/runtime/vm/libcalls.rs:125
vouillon added the bug label to Issue #11489.
cfallin commented on issue #11489:
Thanks -- taking a look!
cfallin commented on issue #11489:
OK, I think the bug is that I didn't account for the tail-call arg region cleanup when computing the SP for a given frame. I had assumed that all function frames are contiguous, so
FP+16(16coming from the unwind trait impl, but that's the value on all our 64-bit platforms) is theSPof the next higher function frame. We use that to load the dynamic context, which we use to compare dynamic tag identities of handlers. Our tail-call ABI has the callee clean up the argument region, since this is necessary to allow arbitrary-to-arbitrary-signature tail calls, and your example has a tail-call from a function of signature(func)to one of signature(func (param i32 i32 i32 i32 i32))(which will go onto the stack on x64, because there are 6 arg regs and we use the first two for caller and callee vmctx). On x64 we use the form of theretinstruction with an SP increment for this (doesn't appear in the disassembly here, but only because$throwends in an unconditional unreachable state because of thethrow).I believe the most robust fix for this is to reference dynamic context off of
FPinstead ofSP-- otherwise we need metadata from functions to know theirFrameLayoutat runtime, which is a much bigger lift. I'll work on that.
Last updated: Dec 06 2025 at 07:03 UTC