Skip to content

gc: test_gap_repsel_gc_stress SIGSEGVs deterministically in 12 matrix arms under #7019's default-on moving minor (PASS -> FAIL) #7022

Description

@proggeramlug

Split out of the post-#7019 matrix re-measurement. New red, attributed to #7019 by A/B on the same source and compiler.

Symptom

test_gap_repsel_gc_stress — the corpus member deliberately built to be GC-live — SIGSEGVs (exit 139) in 12 of 20 arms of scripts/gc_repsel_matrix.sh --arms all --pressure 8. It produces zero stdout lines against an oracle of 7.

The failing arm set is exactly the 12 arms that carry PERRY_CONSERVATIVE_STACK_SCAN=off (directly, or via the %E% evacuating base): evac_minor, force_evac, force_verify, cons_scan_off, cons_scan_off_force, loop_polls, and the six rep_*_off arms. The other 8 arms pass.

This is a PASS → FAIL transition, not an inert cell going red. test-parity/gc_repsel_triage.txt records this file's cons_scan_off cells as green hard gates since #6951, and the last pre-#7019 full matrix (#7015, base 4ad27a15b) had FAIL=20 consisting only of the two #6981 rows.

Attribution — measured, not inferred

Same source, same compiler binary, A/B'd through #7019's own kill switch with PERRY_GC_MOVING_LOOP_POLLS=0 set at both compile and run time (the runtime and codegen halves must match — see the comment on gc_moving_loop_polls_enabled). Config PERRY_GC_HEAP_LIMIT=8 PERRY_GC_INCREMENTAL=0 PERRY_CONSERVATIVE_STACK_SCAN=off:

build exit codes (5 consecutive runs) output
default (#7019 on) 139 139 139 139 139 truncated
PERRY_GC_MOVING_LOOP_POLLS=0 (#7019 off) 0 0 0 0 0 byte-exact vs node 26.5.0

Deterministic, 23/23 crashes observed with #7019 on across repeated batches; 0/11 with it off. Reproduced on two hosts and by the matrix harness itself (exit=139 cycles=27 moved=1727552, identical across all 12 arms and across re-runs).

Where it dies

Immediately after a successful evacuating minor — the last three stderr lines before the fault:

[gc-copy-minor] eligible=true fallback=none
[gc-copy-minor] ran copied_objects=101215 copied_bytes=4594776 promoted_objects=44933 promoted_bytes=2039816 freed_bytes=14384
[gc-step] pre_in_use=10790856 post_in_use=10776472 sweep_freed=14384 block_reclaim=14384 pct=0% step=1073741824→1073741824
[gc] cycle

So relocation completed and the mutator faulted afterwards — the shape of a survivor reference that was moved but not rewritten, or a root the copying minor did not see. Note promoted_objects=44933: this cycle both copies and promotes, so the old-gen handoff path is in play as well.

Why this one matters more than a normal corpus row

gc_stress is the only corpus member that holds each representation-selected local live across escaping allocation churn heavy enough to reach the collector. With it crashing, the 12 arms that were the strongest evidence in the matrix now assert nothing about representation safety under relocation — they assert only that the process dies.

Environment: origin/main @ 4340bffc9, release build, macOS arm64 (reproduced on both a 64 GB and an 8 GB host), node 26.5.0 pinned.

Related: #6981 (same PERRY_CONSERVATIVE_STACK_SCAN=off discriminator, different rows), #6982 (a different, intermittent gc_stress SIGSEGV with the conservative stack scan ON), #7019.

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