You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
instance_private_key_hidden faults under PERRY_GC_SCAVENGE_NURSERY_MB=64 (residual from #7472) #7481
Residual from #7472 (now closed — its headline stringify_object_inner crash was fixed by #7473). At a non-default nursery cap, a different site still faults:
Observed on main @ 351742d (2026-08-06), deterministic at cap=64, absent at the default 16 MB and at 1/4/32 MB post-#7473. The fault address is a garbage pointer (not a NaN-box immediate this time), in the enumeration path's private-key check — likely the same family as #7472's mechanism (a value surviving a large, infrequent copying minor without its slot being rewritten), but at a different consumer.
Not release-blocking (non-default knob), but it is a live copying-minor correctness signal at exactly the cadence #7472 showed the ratchet probes never exercise — a large-Eden probe arm would catch both. Recording it so it does not vanish inside the closed ticket.
The cadence this issue named is now a pinned, gated ratchet probe (#7666) — and the fault itself no longer reproduces
Two separate findings; the second does not close the first.
1. The fault does not reproduce at 7bde3de24 (v0.5.1376)
The reproducer exactly as written here — benchmarks/json_polyglot/bench_field_access.ts, release build, PERRY_RUNTIME_DIR pinned, PERRY_NO_AUTO_OPTIMIZE=1, PERRY_GC_SCAVENGE_NURSERY_MB=64 — exits 0 on 5/5 runs with an identical checksum (2552985550) on the pinned quiet host. No EXC_BAD_ACCESS, no instance_private_key_hidden fault.
And it is not vacuous: at cap 64 that workload still runs 6 copying minors (11 at the default cap), with freed_bytes 38 MB and 34 MB on the large ones. The copying minor was reached; it just no longer produces a bad answer. Which of the ~20 rooting fixes landed between 351742d30 and 7bde3de24 closed it was not bisected.
2. The coverage gap you named is closed, and the shape of it was worse than "no probe"
a large-Eden probe arm would catch both
#7666 adds 13_large_eden_survivors, pinned at PERRY_GC_SCAVENGE_NURSERY_MB=64 through a new per-probe // gc-ratchet-env: declaration that check compares like a metric. It holds a survivor cohort across the minors, takes an old-to-young pointer into that cohort every 256th iteration, and reads all of it back into five separately-diffed output lines, so a missed reference rewrite must fault or print a wrong number.
The finding worth carrying out of this issue: PERRY_GC_SCAVENGE_NURSERY_MB=64 is not, on its own, a larger-Eden knob. On a workload with a small retained set it runs zero copying minors, because gc/policy.rs's arena_growth_full_escalation_due escalates every minor to a full mark-sweep once arena in-use clears its 32 MB floor and exceeds twice the post-full baseline — which a 64 MB Eden over a ~1 MB live set does every time. The first draft of the probe did exactly that (0 copying minors, 4 full sweeps) and would have been pinned on a collector it never reached.
Sizing the retained set is what makes the cadence reachable. Measured on the pinned host:
KEEP
copying minors at 64 MB
at the shipped default
8,192
0
15
131,072
1
14
262,144 (shipped)
4
12
At the shipped size the four minors free 37, 36, 68 and 68 MB — 49.7 MB per minor — and the first copies 532,482 objects (32 MB) in one cycle, against 14.6–16.6 MB per minor on eleven of the twelve default-cap probes (21.8 MB on 12_large_live_set, whose tenured-proportional cap term is the shipped path to a larger Eden and tops out around there).
So your reproducer's cap-64 sensitivity was real for that workload because it carries a live set; a probe copied from a smaller workload would have been silently vacuous. That is why the arm is gated rather than merely present, and why check's liveness rule (minor_cycles > 0 and copied + promoted > 0) is what refuses to pin a shape that stops reaching the copying minor.
Suggested disposition
Close as covered. The specific fault is gone and the cadence it exposed is now pinned, gated, and shown able to fail (deleting the arm's directive, and PERRY_GC_SCAVENGE=0, both turn check red — details in #7666).
Closed by #7666 (v0.5.1379) — the fault no longer reproduces, and the lesson is now a pinned probe.
Re-checked under PERRY_GC_SCAVENGE_NURSERY_MB=64 on the pinned mini: 5/5 exit 0. And the check is not vacuous — the same configuration runs 6 copying minors at cap 64, so the collector this issue is about is demonstrably reached.
More usefully, the lesson is now gated. 13_large_eden_survivors pins the copying-minor cadence the matrix had no coverage of, carrying a per-probe // gc-ratchet-env: PERRY_GC_SCAVENGE_NURSERY_MB=64 declaration that check compares like a metric — an arm whose environment can drift silently is an arm measuring something else.
The finding that shaped the probe is worth recording here, because it nearly produced a probe that measured nothing: a large Eden on a small retained set runs zero copying minors — arena_growth_full_escalation_due escalates every minor to a full sweep above its 32 MB floor. KEEP 8,192 → 0 minors, 131,072 → 1, 262,144 → 4.
Shown able to fail three ways: control OK; env directive deleted → FAILED; PERRY_GC_SCAVENGE=0 → FAILED (minor_cycles 4→0). The first of those matters most — with the directive gone, retention/RSS/wall all read as improvements (−80%, −37%, −27%) because those bands are one-sided, so a probe that gets faster and smaller by not doing its job is indistinguishable from a win.
Activity
docs(engine-plan): 2026-08-06 ticket sync and repsel stack position (#…
proggeramlug commentedon Aug 8, 2026
The cadence this issue named is now a pinned, gated ratchet probe (#7666) — and the fault itself no longer reproduces
Two separate findings; the second does not close the first.
1. The fault does not reproduce at
7bde3de24(v0.5.1376)The reproducer exactly as written here —
benchmarks/json_polyglot/bench_field_access.ts, release build,PERRY_RUNTIME_DIRpinned,PERRY_NO_AUTO_OPTIMIZE=1,PERRY_GC_SCAVENGE_NURSERY_MB=64— exits 0 on 5/5 runs with an identical checksum (2552985550) on the pinned quiet host. NoEXC_BAD_ACCESS, noinstance_private_key_hiddenfault.And it is not vacuous: at cap 64 that workload still runs 6 copying minors (11 at the default cap), with
freed_bytes38 MB and 34 MB on the large ones. The copying minor was reached; it just no longer produces a bad answer. Which of the ~20 rooting fixes landed between351742d30and7bde3de24closed it was not bisected.2. The coverage gap you named is closed, and the shape of it was worse than "no probe"
#7666 adds
13_large_eden_survivors, pinned atPERRY_GC_SCAVENGE_NURSERY_MB=64through a new per-probe// gc-ratchet-env:declaration thatcheckcompares like a metric. It holds a survivor cohort across the minors, takes an old-to-young pointer into that cohort every 256th iteration, and reads all of it back into five separately-diffed output lines, so a missed reference rewrite must fault or print a wrong number.The finding worth carrying out of this issue:
PERRY_GC_SCAVENGE_NURSERY_MB=64is not, on its own, a larger-Eden knob. On a workload with a small retained set it runs zero copying minors, becausegc/policy.rs'sarena_growth_full_escalation_dueescalates every minor to a full mark-sweep once arena in-use clears its 32 MB floor and exceeds twice the post-full baseline — which a 64 MB Eden over a ~1 MB live set does every time. The first draft of the probe did exactly that (0 copying minors, 4 full sweeps) and would have been pinned on a collector it never reached.Sizing the retained set is what makes the cadence reachable. Measured on the pinned host:
KEEPAt the shipped size the four minors free 37, 36, 68 and 68 MB — 49.7 MB per minor — and the first copies 532,482 objects (32 MB) in one cycle, against 14.6–16.6 MB per minor on eleven of the twelve default-cap probes (21.8 MB on
12_large_live_set, whose tenured-proportional cap term is the shipped path to a larger Eden and tops out around there).So your reproducer's cap-64 sensitivity was real for that workload because it carries a live set; a probe copied from a smaller workload would have been silently vacuous. That is why the arm is gated rather than merely present, and why
check's liveness rule (minor_cycles > 0andcopied + promoted > 0) is what refuses to pin a shape that stops reaching the copying minor.Suggested disposition
Close as covered. The specific fault is gone and the cadence it exposed is now pinned, gated, and shown able to fail (deleting the arm's directive, and
PERRY_GC_SCAVENGE=0, both turncheckred — details in #7666).test(gc-ratchet): pin the large-Eden copying-minor cadence (#7481) an…
test(gc-ratchet): pin the large-Eden copying-minor cadence (#7481) an…
proggeramlug commentedon Aug 9, 2026
Closed by #7666 (v0.5.1379) — the fault no longer reproduces, and the lesson is now a pinned probe.
Re-checked under
PERRY_GC_SCAVENGE_NURSERY_MB=64on the pinned mini: 5/5 exit 0. And the check is not vacuous — the same configuration runs 6 copying minors at cap 64, so the collector this issue is about is demonstrably reached.More usefully, the lesson is now gated.
13_large_eden_survivorspins the copying-minor cadence the matrix had no coverage of, carrying a per-probe// gc-ratchet-env: PERRY_GC_SCAVENGE_NURSERY_MB=64declaration thatcheckcompares like a metric — an arm whose environment can drift silently is an arm measuring something else.The finding that shaped the probe is worth recording here, because it nearly produced a probe that measured nothing: a large Eden on a small retained set runs zero copying minors —
arena_growth_full_escalation_dueescalates every minor to a full sweep above its 32 MB floor.KEEP8,192 → 0 minors, 131,072 → 1, 262,144 → 4.Shown able to fail three ways: control OK; env directive deleted → FAILED;
PERRY_GC_SCAVENGE=0→ FAILED (minor_cycles4→0). The first of those matters most — with the directive gone, retention/RSS/wall all read as improvements (−80%, −37%, −27%) because those bands are one-sided, so a probe that gets faster and smaller by not doing its job is indistinguishable from a win.