Summary
With the stack-switching proposal enabled, once a resume has 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 with free(): invalid pointer / munmap_chunk(): invalid pointer (SIGABRT). The resume is the trigger; no exceptions are involved in the minimal repro below. A resume that returns normally (process exits 0) is fine.
Steps to Reproduce
Minimal .wat (no exceptions, just cont.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.wasm
Expected Results
The continuation runs to completion, resume returns to $start, and proc_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 pointer
The same crash occurs if, instead of proc_exit, the post-resume code traps (e.g. unreachable / integer divide-by-zero) or lets an uncaught exception reach the host. cont.new without resume followed by proc_exit does not crash, so resume is the trigger. Guest-side attempts to clear state (nulling the cont local, clearing the table slot, nesting the workload in a child continuation, calling proc_exit from 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=y
Context
This is hit in practice by a language that compiles effect handlers to stack switching: any program that combines a with @k-style handler (a resume) with a later trap or uncaught-exception/proc_exit termination aborts instead of exiting cleanly. Programs that only ever exit 0 after a resume are 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-resume double-free, so opening one with a self-contained repro.
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):Expected 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:
munmap_chunk(): invalid pointerfree(): 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
-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.