gc: refuse native roots off aarch64, and stop the ELF map forcing DT_TEXTREL - #7324
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 (3)
📝 WalkthroughWalkthroughThe compiler now rejects native GC map assembly on non-AArch64 targets and emits writable, retained ELF GC map sections. The workflow and changelog document ARM64 validation and the target restriction. ChangesNative GC ARM64 support
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/perry-codegen/src/gc_map.rs (1)
65-76: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winAdd regression assertions for the ELF hardening properties.
The
"awR"declaration addsSHF_WRITEandSHF_GNU_RETAIN. The ARM gate currently checks only section presence and removal of.llvm_stackmaps. A regression to read-only flags could pass while reintroducingDT_TEXTREL. Add checks for a writable.perry_gcmapsection and the absence ofTEXTREL.As per coding guidelines, the CI gate must assert that the behavior it measures actually executed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/perry-codegen/src/gc_map.rs` around lines 65 - 76, Extend the ARM ELF regression gate around the existing section-presence and .llvm_stackmaps checks to verify that .perry_gcmap has writable flags and that the linked binary contains no TEXTREL entry. Ensure the gate also asserts that these inspection checks actually ran, rather than passing when the relevant ELF metadata or tool output is missing.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/perry-codegen/src/gc_map.rs`:
- Around line 65-76: Extend the ARM ELF regression gate around the existing
section-presence and .llvm_stackmaps checks to verify that .perry_gcmap has
writable flags and that the linked binary contains no TEXTREL entry. Ensure the
gate also asserts that these inspection checks actually ran, rather than passing
when the relevant ELF metadata or tool output is missing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 3345b1f6-4620-4fdd-890f-0099b4334714
📒 Files selected for processing (3)
.github/workflows/gc-native-roots.ymlchangelog.d/7321-statepoints-aarch64-only.mdcrates/perry-codegen/src/gc_map.rs
…TEXTREL The gc-native-roots gate went red on main with a SIGSEGV rather than a missing section: SHF_GNU_RETAIN did keep .perry_gcmap through --gc-sections and .llvm_stackmaps was gone, so the ELF retention fix worked. Two defects behind the crash. The backend is aarch64-only and did not say so. Cross-compiled a probe to x86_64-unknown-linux-gnu and decoded the emitted map: all 178 root slots are Indirect [RSP + off], DWARF register 7. chain_walkable admits only aarch64's 29/31, so every frame falls back to the unwinder, which resolves the base with _Unwind_GetGR(ctx, 7) — that does not reliably return the stack pointer (_Unwind_GetCFA is the supported way). Wild addresses, then a segfault when the collector writes through them. The mode is opt-in, so refuse rather than ship a binary that crashes under collection. The ELF section was read-only while holding relocated function addresses: ld warned 'relocation against main in read-only section .perry_gcmap' and created a DT_TEXTREL in a PIE. Now "awR". Gate moves to an ARM64 runner — on x86-64 it would now test only the refusal. macOS arms remain 9/9; x86-64 Linux now fails the compile with a message naming the target instead of segfaulting at collection time.
571cad9 to
806e379
Compare
…at it found (#7334) The diagnostic job was merged with #7331 before it had served its purpose; it has now, so it comes out. Its answer contradicts the narrative still at the top of this file: the compact-map rewriter parses x86-64 stack maps fine. Every root is Indirect [RSP + off] (DWARF 7), round-tripping through the explicit- register tag, and no clang version or -march setting reproduced a parse failure. The x86-64 defect is at collection time, which #7324 refuses for. Replace the wrong explanation rather than leave two contradictory ones in the same header. Co-authored-by: Ralph Küpper <ralph@skelpo.com>
The
gc-native-rootsgate went red onmainafter #7314. Good news first: the ELF question it existed to answer is resolved —SHF_GNU_RETAINdid keep.perry_gcmapthrough--gc-sections, and.llvm_stackmapswas gone. Both section assertions passed.It failed with exit 139 — SIGSEGV on
02_survivor_promotion, the evacuation-heaviest probe. Two separate defects.The backend is aarch64-only and did not say so
The runner is x86-64. I cross-compiled a probe to
x86_64-unknown-linux-gnuand decoded the emitted stack map rather than guessing:Every root is
Indirect [RSP + off]— DWARF register 7. The runtime'schain_walkableadmits only aarch64's FP/SP (29 and 31), so on x86-64 it is always false and every frame falls back to the unwinder, which resolves the base with_Unwind_GetGR(ctx, 7). That call does not reliably return the stack pointer —_Unwind_GetCFAis the supported way to obtain it. So the walker computed wild addresses and the collector segfaulted writing through them.The mode is opt-in, so the compiler now refuses the combination with a message naming the target, rather than emitting a binary that crashes under collection. Verified:
--target linuxwithPERRY_STATEPOINTS=1now fails the compile cleanly.Making x86-64 actually work means per-architecture base resolution (
_Unwind_GetCFAfor SP, per-arch DWARF constants) — real work, tracked under #7173, and not something to fake in a refusal.The ELF section was read-only but holds relocated addresses
The section carries
.quad <function symbol>entries the loader must relocate. WithoutSHF_WRITEthat forces a text relocation in a PIE — a hardening regression and a portability hazard independent of the segfault. Now"awR"(ALLOC | WRITE | RETAIN).The gate moves to ARM64
ubuntu-24.04-arm. On x86-64 the gate would now exercise nothing but the refusal; on ARM64 it tests the configuration that is actually supported and still answers what it was built for — whether the compact map survives ELF linking.Verification
macOS arms unchanged: explicit bridge, RS4GC and the default shadow stack all 9/9 against the pinned Node oracle, statepoint arms under forced evacuation with the verifying walker.
Summary by CodeRabbit
Bug Fixes
Documentation