Skip to content

codegen: SIGBUS in LLVM statepoint lowering makes next@16.3.0's jsonwebtoken bundle uncompilable at every opt level #8145

Description

@proggeramlug

Summary

On origin/main (0a1e78e5f), next@16.3.0's bundled jsonwebtoken
(dist/compiled/jsonwebtoken/index.js, sha256 056c2ddd…a6b9 — the #8132
fixture) cannot be compiled at any optimization level while precise roots
lower to statepoints. Both arms die with the same fault:

EXC_BAD_ACCESS (SIGBUS), KERN_PROTECTION_FAILURE
  llvm::AArch64TargetLowering::LowerCall(...)
  llvm::TargetLowering::LowerCallTo(...)
  llvm::SelectionDAGBuilder::lowerInvokable(...)
  llvm::SelectionDAGBuilder::LowerAsSTATEPOINT(...)
  llvm::SelectionDAGBuilder::LowerStatepoint(...)
  ...
  perry_codegen::inprocess::optimize_and_emit_module
arm outcome
-Os (today's default for this unit) SIGBUS at 292 s (261 s CPU)
-O0 (PERRY_LL_SIZE_OPT=0) SIGBUS at 120-208 s
PERRY_RS4GC=0, -O0 succeeds, 20.2 s, 6.6 MB dylib
PERRY_RS4GC=0, -Os succeeds, 48.6 s, 4.3 MB dylib
PERRY_LLVM_INPROCESS=0 (text backend) clang: error: unterminated attribute group at line 2034949 of the 414 MB rendered unit

4/4 reproductions of the SIGBUS.

It is not a stack overflow

The faulting address lands inside a reserved, never-mapped VM range (the
GPU Carveout span in the crash report's vmRegionInfo), not on a stack guard
page. Raising the codegen worker stack from the std default (2 MiB, these are
std::thread::scope spawns in native_emit.rs) to 1 GiB changed nothing: same
site, same signal, same timing. RUST_MIN_STACK=268435456 likewise.

Peak footprint at the crash is ~2.5 GB, so it is not a plain OOM either.

The input is the one #8132 describes: 21,774 statepoints and 1.5M gc.relocates
after RS4GC, mean 83 operands per statepoint, max 426.

Why it matters

#8132 records -O0 on this bundle as "2m46.5s, 40 MB dylib". That does not
reproduce on 0a1e78e5f.
Any plan that routes this unit to -O0 — including
the opt-level-threshold direction in #8132 (see #8144, where it is measured and
declined) — therefore swaps a hang for a crash, and does not unblock #8040.

The other two #8132 directions (reduce values live across safepoints; split the
monolith) both attack this as well, since both shrink the statepoint operand
lists this is choking on.

Reproduction

npm i next@16.3.0
cp node_modules/next/dist/compiled/jsonwebtoken/index.js /tmp/fx/jwt.js
printf '{"name":"fx","version":"1.0.0","private":true}\n' > /tmp/fx/package.json
PERRY_NO_AUTO_OPTIMIZE=1 PERRY_LL_SIZE_OPT=0 \
  perry compile /tmp/fx/jwt.js -o /tmp/fx/app --output-type dylib

Environment: arm64 macOS 26.5, LLVM 22.1.4, Apple clang 21.0.0, compiler built
--profile perry-dev. Not yet checked against a --release/dist build.

Refs #8132, #8040.

Activity

  1. proggeramlug commented on Aug 15, 2026

    @proggeramlug
    ContributorAuthor

    This is #8121, and it is already fixed in the open draft PR #8123 — the baseline used here (0a1e78e5f) predates that fix.

    The stack quoted here is #8121's exact signature: AArch64TargetLowering::LowerCall under SelectionDAGBuilder::LowerAsSTATEPOINT / LowerStatepoint, faulting on an address in reserved, never-mapped space, and unaffected by worker stack size.

    Cause: RS4GC rewrites every non-leaf call in a gc "statepoint-example" function into a gc.statepoint. Perry's issue-#74 loop-preservation barrier is call void asm sideeffect "", ""(), so RS4GC used the InlineAsm itself as the statepoint's callee operand — invalid IR (Cannot take the address of an inline asm!). optimize_and_emit verified the module before the rewrite but not after, so it reached SelectionDAG and took the compiler down instead of reporting anything.

    That also explains the "does not reproduce" note against #8132's recorded -O0 figure. Those numbers (2m46.5s, 40 MB dylib, PERRY_RS4GC=1) were measured with #8123 applied; without it, no arm produces a binary. Checking 0a1e78e5f: it contains a gc-leaf-function mention from #7982 (a trailing-attribute concern on typed calls) but not the mark_gc_leaf helper #8123 adds, so the fix is genuinely absent there.

    The text-backend failure noted here (clang: unterminated attribute group) is the separate LLVM version-skew problem inprocess::optimize_and_emit documents — Homebrew 22 emitting constructs Apple clang 21 rejects — not this bug.

    Suggest closing as a duplicate of #8121 once #8123 lands. The -Os/-O0 measurements gathered in #8144 stand on their own and are unaffected: they were taken with PERRY_RS4GC=0, where this crash cannot occur.

  2. proggeramlug commented on Aug 16, 2026

    @proggeramlug
    ContributorAuthor

    The SIGBUS is fixed on 3be2016c1 — but not by the PR referenced earlier in this thread. #8123 is CLOSED, never merged. The fix landed as e34b84029 (#8128), "unbreak in-process RS4GC on inline asm and relocation-grown functions", verified an ancestor of main.

    Evidence on main:

    • crates/perry-codegen/src/inst.rs:287 emits the loop barrier as call void asm sideeffect "", ""() "gc-leaf-function", so RS4GC no longer statepoint-wraps the inline-asm barrier.
    • crates/perry-codegen/src/inprocess.rs:555 holds the regression test gc_leaf_asm_barrier_survives_rs4gc_unwrapped.
    • git grep mark_gc_leaf origin/main returns nothing, confirming the helper name cited earlier is stale.

    Scoping the close honestly: this issue is the SIGBUS, and the SIGBUS is gone. Compilability of the next@16.3.0 jsonwebtoken bundle in usable time is a separate, still-open problem — #8161's changelog records one generated chunk at ~112 min in a single codegen unit, and #8144 measured the opt-level retune and deliberately declined it. That belongs to #8144/#8040, not here.

    Closing on the crash.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions