fix(gc): the evacuation verifier released its malloc-registry borrow before validating malloc-backed parents (PERRY_GC_VERIFY_EVACUATION re-entered the RefCell) - #9965
Draft
proggeramlug wants to merge 5 commits into
Conversation
Snapshot malloc-backed headers before running verifier callbacks so exact child validation can lazily rebuild the malloc registry without re-entering its RefCell borrow. Add a worker-thread copying-minor regression fixture. Claude-Session: https://claude.ai/code/session_011dhBmdn4vGgNibjo3oZqTo
Record the re-entrancy path, structural fix, disk-gated validation status, and the requested perrymaster campaign handoff. Claude-Session: https://claude.ai/code/session_011dhBmdn4vGgNibjo3oZqTo
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks 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 |
added 3 commits
September 7, 2026 15:31
Name heap parents, layout slots, root scanners, and collection coverage when evacuation verification finds a stale forwarding alias. Emit a compact success witness with heap-walk and remembered-edge counts under GC diagnostics. Add focused failure-attribution and success-line regression tests. Claude-Session: https://claude.ai/code/session_011dhBmdn4vGgNibjo3oZqTo
Record VF2 field derivation, covered failure sites, passing-path cost, focused test evidence, disk-limited gates, and the perrymaster campaign request. Claude-Session: https://claude.ai/code/session_011dhBmdn4vGgNibjo3oZqTo
Re-pin the PASS1_MARKED non-moving window after auditing the verifier diagnostic plumbing, and classify its three counter-only TLS holders. Claude-Session: https://claude.ai/code/session_011dhBmdn4vGgNibjo3oZqTo
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.
Diagnostic-only runtime fix, on
origin/main8b7dc33. Written by codex from the campaign's ATX run; gates not yet run locally (dev-box disk under the 12 GB floor when the task ran) — perrymaster's gate ladder and a 4-turn cc run underPERRY_GC_VERIFY_EVACUATION=1are the acceptance.Why
With
PERRY_GC_VERIFY_EVACUATION=1, a copying minor on cc dies in its own verifier:gc/malloc.rs:527 RefCell already borrowed. The verifier held a shared borrow of the thread-localMALLOC_STATEwhile iteratings.objects; each malloc-backed parent's slot validation (verify_old_young_parent_slots_covered→visit_gc_rewrite_slots→verify_old_young_slot_covered) can reachremembered_child_needs_tracking→gc_malloc_header_is_tracked, whoseensure_set_builttakes a mutable borrow of the sameRefCellto rebuild the exact-lookup set. Same thread, nested borrow, panic — before the verifier has inspected anything. The campaign needed this arm to discriminate an intermittent cc TypeError seen under #9951 (2 of 7 runs) and the arm could not run.Production callers of the exact-membership helper (
barrier/mod.rs,young_log.rs,native_handle.rs,timer.rs,path.rs,symbol/get.rs,value/dyn_index.rs,json/stringify.rs) were audited: none holds aMALLOC_STATEborrow across the call. The re-entrancy is verifier-only.What changes
gc/verify.rs: one helper snapshots the malloc header vector and releases the borrow before any verifier callback. Every verifier-owned malloc walk uses it: the old→young edge check, marked-child checks, array-slot enumeration, and the final evacuation heap walk. Validation semantics unchanged — notry_borrowfallback, no weakened pointer check.changelog.d/verify-evacuation-malloc-borrow.md.Test (named; sabotage stated)
gc::tests::copying::verify_malloc_borrow::test_copied_minor_verify_evacuation_releases_malloc_registry_before_validation— on a spawned worker thread: malloc-backed closure parent → malloc-backed child, registry made inactive with a non-empty side table, asserts the exact lookup's rebuild count advances by one duringverify_old_to_young_edges_collect, then completes a copying minor with evacuation verification on (a nursery object copied; bothevacuation_verifyandold_young_edge_verifyphases present). Sabotage: put the verifier loop back underMALLOC_STATE.with(...borrow())— the child lookup'sborrow_mut()panics the worker andjoin().expect(...)fails.Gates
rustfmt --checkandgit diff --checkonly (disk floor). Not run: the named test,cargo test -p perry-runtime --release --lib -- --test-threads=1,cargo build --release -p perry-runtime --features wasm-host.PERRY_GC_VERIFY_EVACUATION=1; the run must complete all four turns with verifier output present and noRefCell already borrowed/panic.GC-adjacent: needs the
run-extended-testslabel.VF2 (1ec9e0e): the parent names itself
On perrymaster the fixed verifier ran 4 cc turns on main without a panic and, on the #9951 runtime, caught a real fault in 1 of 3 runs:
stale forwarded pointer in heap fieldsat the first minor after a budgeted sweep. The panic named only slot/old/forwarded_to. The second commit makes every stale-forwarding panic (heap rewrite descriptors, remembered dirty ranges, shadow-stack/stack-map/global roots, the named Rust and FFI root scanners, the runtime side-table visitor paths) one line withparent= parent_type= parent_space=(old_page|nursery_from|nursery_to|promoted_in_place_this_cycle|malloc|pinned) slot_index= visitor= child_type= child_space= remembered= young_logged= dirty_snapshot= minor= trigger= after_budgeted_step= surface=, all derived on the cold failure path only (the passing per-slot closure is unchanged). UnderPERRY_GC_DIAG=1a passing copied minor prints[gc-verify] minor=N evacuation_ok parents= slots= old_young_edges=so a clean run proves the verifier was live. Tests:stale_forwarded_reference_panic_names_parent_slot_and_coverage,evacuation_verifier_pass_line_counts_parents_and_slots(new modulegc/tests/copying/verify_parent_context.rs). Local gates on the second commit are partial (disk): the focused verifier gate passed 16 before the final cleanup; the final rerun, full lib suite and archive build run on perrymaster's ladder (stage VF2: 6 four-turn cc runs each on main+fix and #9951+fix with the verifier on).Measured (perrymaster VF2, 2026-09-07)
Gate on the box at 38229cc: runtime lib suite 3,250 passed / 0 failed one thread (42 verifier-named tests ok), archive feature set rc 0. Twelve 4-turn cc runs (6 on main + this, 6 on the #9951 runtime + this, interleaved) with
PERRY_GC_VERIFY_EVACUATION=1 PERRY_GC_DIAG=1: 0 verifier failures, 0 panics, 0 non-diagnostic stderr lines, all 48 turns completed. Liveness on every copying minor (25–27[gc-verify] minor=N evacuation_oklines per run; e.g. minor 9: parents=735,640 slots=4,106,513 old_young_edges=55). The verifier's cost is ≈ +1.3 s per turn; RSS unchanged. The stale-forwarded-pointer fault first seen on the #9951 runtime is now 1 of 9 verifier runs there and 0 of 7 on main; it did not recur under the attributing verifier, so no parent line exists yet — the instrument stays armed on that family.https://claude.ai/code/session_011dhBmdn4vGgNibjo3oZqTo