Nymphium opened issue #13584:
Summary
With the stack-switching proposal enabled, once a
resumehas executed, any subsequent host-ward unwind —proc_exit, a wasm trap, or an uncaught exception reaching the host — corrupts the fiber/stack allocator and aborts the process withfree(): invalid pointer/munmap_chunk(): invalid pointer(SIGABRT). Theresumeis the trigger; no exceptions are involved in the minimal repro below. Aresumethat returns normally (process exits 0) is fine.Steps to Reproduce
Minimal
.wat(no exceptions, justcont.new+resume+proc_exit):(module (import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32))) (memory (export "memory") 1) (type $ft (func)) (type $ct (cont $ft)) (func $body) (elem declare func $body) (func $start (local $k (ref null $ct)) ref.func $body cont.new $ct local.set $k block $done (resume $ct (local.get $k)) br $done end i32.const 0 call $proc_exit) (start $start))$ wasm-tools parse ss.wat -o ss.wasm $ wasmtime run -W exceptions=y,function-references=y,stack-switching=y,tail-call=y ss.wasmExpected Results
The continuation runs to completion,
resumereturns to$start, andproc_exit(0)exits the process cleanly with code 0.Actual Results
Process aborts (SIGABRT, exit 134) with a heap-allocator error:
- wasmtime 45.0.0:
munmap_chunk(): invalid pointer- wasmtime 44.0.0:
free(): invalid pointerThe same crash occurs if, instead of
proc_exit, the post-resumecode traps (e.g.unreachable/ integer divide-by-zero) or lets an uncaught exception reach the host.cont.newwithoutresumefollowed byproc_exitdoes not crash, soresumeis the trigger. Guest-side attempts to clear state (nulling the cont local, clearing the table slot, nesting the workload in a child continuation, callingproc_exitfrom within a fiber) all still crash — the corruption appears to live in the per-store stack allocator.Versions and Environment
- Wasmtime: 44.0.0 and 45.0.0 (both reproduce), x86_64 Linux
- Flags:
-W exceptions=y,function-references=y,stack-switching=y,tail-call=yContext
This is hit in practice by a language that compiles effect handlers to stack switching: any program that combines a
with @k-style handler (aresume) with a later trap or uncaught-exception/proc_exittermination aborts instead of exiting cleanly. Programs that only ever exit 0 after aresumeare unaffected.Filing as a distinct case under the stack-switching tracking issue (#10248). It seems related to the existing "Stack-switching crash with traps and missing bounds checks" item and to the note there that hostcalls from continuation stacks "should not be allowed", but I didn't find a dedicated issue for the
proc_exit/host-unwind-after-resumedouble-free, so opening one with a self-contained repro.
alexcrichton added the wasm-proposal:stack-switching label to Issue #13584.
alexcrichton commented on issue #13584:
Thanks for the report, and stack-switching is known to be incomplete and is not recommended for users to enable at this point.
dhil commented on issue #13584:
This issue will be fixed by #11717. I can add the POC as a regression test.
dhil commented on issue #13584:
This issue can be closed now, as it was fixed by #11717. I have added the POC as a regression test in #13996.
alexcrichton closed issue #13584:
Summary
With the stack-switching proposal enabled, once a
resumehas executed, any subsequent host-ward unwind —proc_exit, a wasm trap, or an uncaught exception reaching the host — corrupts the fiber/stack allocator and aborts the process withfree(): invalid pointer/munmap_chunk(): invalid pointer(SIGABRT). Theresumeis the trigger; no exceptions are involved in the minimal repro below. Aresumethat returns normally (process exits 0) is fine.Steps to Reproduce
Minimal
.wat(no exceptions, justcont.new+resume+proc_exit):(module (import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32))) (memory (export "memory") 1) (type $ft (func)) (type $ct (cont $ft)) (func $body) (elem declare func $body) (func $start (local $k (ref null $ct)) ref.func $body cont.new $ct local.set $k block $done (resume $ct (local.get $k)) br $done end i32.const 0 call $proc_exit) (start $start))$ wasm-tools parse ss.wat -o ss.wasm $ wasmtime run -W exceptions=y,function-references=y,stack-switching=y,tail-call=y ss.wasmExpected Results
The continuation runs to completion,
resumereturns to$start, andproc_exit(0)exits the process cleanly with code 0.Actual Results
Process aborts (SIGABRT, exit 134) with a heap-allocator error:
- wasmtime 45.0.0:
munmap_chunk(): invalid pointer- wasmtime 44.0.0:
free(): invalid pointerThe same crash occurs if, instead of
proc_exit, the post-resumecode traps (e.g.unreachable/ integer divide-by-zero) or lets an uncaught exception reach the host.cont.newwithoutresumefollowed byproc_exitdoes not crash, soresumeis the trigger. Guest-side attempts to clear state (nulling the cont local, clearing the table slot, nesting the workload in a child continuation, callingproc_exitfrom within a fiber) all still crash — the corruption appears to live in the per-store stack allocator.Versions and Environment
- Wasmtime: 44.0.0 and 45.0.0 (both reproduce), x86_64 Linux
- Flags:
-W exceptions=y,function-references=y,stack-switching=y,tail-call=yContext
This is hit in practice by a language that compiles effect handlers to stack switching: any program that combines a
with @k-style handler (aresume) with a later trap or uncaught-exception/proc_exittermination aborts instead of exiting cleanly. Programs that only ever exit 0 after aresumeare unaffected.Filing as a distinct case under the stack-switching tracking issue (#10248). It seems related to the existing "Stack-switching crash with traps and missing bounds checks" item and to the note there that hostcalls from continuation stacks "should not be allowed", but I didn't find a dedicated issue for the
proc_exit/host-unwind-after-resumedouble-free, so opening one with a self-contained repro.
Last updated: Jul 29 2026 at 05:03 UTC