Skip to content

Stack switching: host-ward unwind (proc_exit / trap) after a resume double-frees a fiber stack (44.0.0 + 45.0.0) #13584

@Nymphium

Description

@Nymphium

Summary

With the stack-switching proposal enabled, once a resume has executed, any subsequent host-ward unwindproc_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions