Skip to content

aarch64: Wrong unwind info and panics on Windows #14939

Open

Description

@alexcrichton

This test:

test unwind
set unwind_info
target aarch64-pc-windows-msvc

function %f() preserve_all {
    fn0 = %g()

block0:
    call fn0()
    return
}

fails with:

$ cargo run -p cranelift-tools -- test preserve-all.clif

thread 'worker #N' panicked at cranelift/codegen/src/isa/unwind/winarm64.rs:263:33:
Can't save registers before X19
FAIL preserve-all.clif: panicked in worker #N: Can't save registers before X19
1 tests
Error: 1 failure

This module:

(module
  (type $t (func (param i32) (result i32)))
  (table funcref (elem $g))
  (func $g (type $t) local.get 0 i32.const 1 i32.add)
  (func (export "f") (param i32) (result i32)
    local.get 0
    i32.const 0
    return_call_indirect (type $t)))

fails with guest debugging enabled:

$ cargo run --features all-arch -- compile --target aarch64-pc-windows-msvc -D guest-debug=y retcall_ind.wat

thread '<unnamed>' panicked at cranelift/codegen/src/isa/unwind/winarm64.rs:263:33:
Can't save registers before X19

Without guest debugging it compiles, but its unwind info is wrong:

$ cargo run --features all-arch -- compile --target aarch64-pc-windows-msvc retcall_ind.wat
$ aarch64-linux-gnu-objdump -d retcall_ind.cwasm
0000000000000020 <wasm[0]::function[1]>:
      20:	a9bf7bfd 	stp	x29, x30, [sp, #-16]!
      24:	910003fd 	mov	x29, sp
      28:	f8408050 	ldur	x16, [x2, #8]
      2c:	f8418210 	ldur	x16, [x16, #24]
      30:	91008210 	add	x16, x16, #0x20
      34:	eb3063ff 	cmp	sp, x16
      38:	54000363 	b.cc	a4 <wasm[0]::function[1]+0x84>
      3c:	a9bf6bf3 	stp	x19, x26, [sp, #-16]!
      ...
$ aarch64-linux-gnu-objcopy -O binary --only-section=.xdata retcall_ind.cwasm retcall_ind.xdata
$ xxd -g1 retcall_ind.xdata | head -2
00000000: 05 00 00 08 e1 81 00 00 23 00 00 08 cc 01 e1 81  ........#.......
00000010: 3a 00 00 30 01 da 01 da 81 db 01 db 81 cc 01 cc  :..0............

The .xdata entry for function[1] is at offset 0x8, and its unwind codes
are cc 01 e1 81:

  • cc 01 is save_regp_x x19, x20, [sp, #-16]!, but the prologue saves x19, x26.
  • There's no end (e4) code. The next function's header (3a 00 00 30) follows immediately.
  • The stack-limit check at 0x28-0x38 has no codes, so the codes don't map one-to-one to prologue instructions.
LLM summary, if helpful

All three are in cranelift/codegen/src/isa/unwind/winarm64.rs:

  • preserve_all panic: Windows arm64 unwind codes can only describe
    saves of x19-x28 and d8-d15 (short of save_any_xreg), and
    create_unwind_info panics on anything else. preserve_all saves
    x0-x17 too, and Wasmtime uses it for the guest-debug breakpoint
    trampoline.
  • Non-consecutive pair: the prologue saves callee-saved registers two
    at a time in sorted order, and regalloc2 doesn't hand them out
    consecutively, so stp x19, x26 happens. The two SaveReg records are
    merged into one save_regp_x, which can only express x(N), x(N+1), and
    the second register is dropped. An SEH unwinder would restore x20 from
    x26's slot and leave x26 alone.
  • No end code / not one-to-one: emit writes only the prologue
    codes, never end, and no nop codes for prologue instructions that
    don't change unwind state (bti c, the stack-limit check, the tail-call
    frame move, multi-instruction SP adjustments). The format requires both
    for unwinding from inside a prologue. Wasmtime's own unwinding uses
    frame pointers, so this affects only SEH-based tools (debuggers, ETW,
    RtlVirtualUnwind). None of this was tested on Windows.

Activity

  1. added
    bugIncorrect behavior in the current implementation that needs fixing
    craneliftIssues related to the Cranelift code generator
    on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIncorrect behavior in the current implementation that needs fixingcraneliftIssues related to the Cranelift code generatorcranelift:area:aarch64Issues related to AArch64 backend.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions