fix(gc): the statepoint bridge must refuse an invoke it cannot root (#7327) - #7330
Merged
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe explicit statepoint bridge now detects ChangesInvoke statepoint handling
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Aug 3, 2026
proggeramlug
pushed a commit
that referenced
this pull request
Aug 3, 2026
…echanism
Two corrections and one measurement.
The gap suite re-run against RS4GC in-process, two arms per test
(shadow-stack control + RS4GC), 479/479: 447 pass->pass, 19 pre-existing
diffs unchanged, 13 node_fail, ZERO new regressions, ZERO refusals, ZERO
compile failures. Zero refusals is the load-bearing number -- 128 of the
479 tests contain `try {}` and the bridge cannot compile any of them.
The earlier soak's "13 regressions, do not flip" was measured against
the bridge, before #7329/#7330, on a backend that structurally cannot
compile a quarter of the suite. It should not be carried forward.
And the x86-64 mechanism was wrong. The workflow comment claimed
_Unwind_GetGR(ctx, 7) "does not reliably return the stack pointer".
Measured on x86-64 Linux (glibc 2.39, gcc 13.3.0): it SEGFAULTS. RBX,
RBP and RIP return correctly; RAX and RSP both SIGSEGV, because libgcc
tracks only the columns CFI restores and RSP is derived from the CFA
rather than tracked. The fault is in the call itself, so no address
validation after it can help -- the previous wording pointed at the
wrong fix. Details and a reproducer in #7333.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7327.
The defect
The bridge's line classifier matched only
call:An
invoketherefore skipped both the statepoint conversion and the fail-closedpanic!below it, and passed through as an ordinary line.Since #7302 moved exception lowering to
invoke/landingpad, that is every call inside atry. Measured on one program: 58 invokes, 0 carryinggc.statepoint, with allocating callees among them —js_object_alloc_class_inline_keys,js_array_push_f64,js_native_call_method_by_id. Those frames had no roots at all.The instrument was blind to it too
--statepoint-reportcounts only lines it recognises, so "0 parser fallbacks" said nothing about any call inside atry— including in #7314's headline census (23,301 safepoints, 0 fallbacks). Invokes are now counted, so the census stops overstating its own coverage.Why refuse rather than implement
Forming a statepoint from an invoke is real work: the statepoint must itself become an
invoke, withgc.resultand the relocates in the normal successor. RS4GC already does this correctly.Until the bridge does, refusing is the same fail-closed rule the plain stack-map fallback was deleted for in #7314 — "a loud compile failure beats silent heap corruption." The refusal is scoped: it fires only when the invoke actually has live roots across it and the callee is neither an
llvm.*intrinsic nor in the audited cannot-collect table.Verified
trystill compiles under the bridge — the refusal does not over-fire.precise_rootstests pass; file-size, GC store-site, addr-class gates green;cargo fmtclean.What this exposes — worth reading
There is currently no working statepoint path for try-carrying code on a default toolchain. RS4GC handles invokes, but on this machine it fails with Apple clang 21:
and needs
PERRY_LLVM_CLANGpointed at a version-matched LLVM 22. Verified pre-existing — it fails identically with an unmodified binary built before this change. The diagnostic says so rather than sending people to a backend that will not build for them.That gap matters for the shadow-stack removal plan: exceptions are not an edge case, so either the bridge learns invokes or RS4GC becomes reliably usable.
Not verified
Whether this clears any of the 13 gap-suite regressions the statepoint soak found — it converts them from silent wrong answers into compile refusals, which is an improvement in kind but not a pass. Measuring that needs the bridge to actually support invokes.
Summary by CodeRabbit
Bug Fixes
invokeinstructions during statepoint processing.Documentation