Repository navigation
fix(gc): one liveness rule for minor side-allocation owners; live Map stores survive in-place promotion - #12142
Merged
Merged
Conversation
added 2 commits
October 7, 2026 07:20
An untraced in-place promotion marks nothing, but the from-space Map walk ran before the retagged blocks left the young arenas and read every unmarked Map on them as dead. It freed the store of live Maps, and the next set wrote through a null store (SIGSEGV). Add gc::minor_side_owner_is_dead(header, space): dead only when the owner is unmarked, unforwarded, unpinned and untenured, and its block is from-space. The Map walk, Set, Error diagnostics, lazy JSON tapes, promise contexts and the address-keyed side-table prune all ask it.
Witness: an untraced in-place promotion with a rooted Map and a dropped 131k-entry Map must free no store and leave the live Map usable. A traced companion checks the dead Map is still reclaimed by the next full. Count Map side-storage frees per thread as well, so the map_store tests assert exact deltas while other test threads free Maps in parallel. Gap test: four 160k object-key cohorts, each dropping the last.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing (11)
✨ 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 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.
Closes #12141.
During an untraced in-place promotion, the copying minor's side-allocation finalize treated every unmarked Map in the promoted blocks as dead. Untraced promotion marks nothing, so it freed the native store of live Maps, and the next
map.setwrote through a NULL store. Any program whose Maps grow past about 131k entries while young blocks are promoted in place could hit it. It predates #12132.Fix: one liveness rule
gc/dead_owner.rshasminor_side_owner_is_dead(header, space). It returns dead only if the block is minor from-space (Eden or the active survivor half), the object is an arena object, and it is not MARKED, FORWARDED, PINNED or TENURED.PromotedYoungbefore the finalize runs, so their objects are never "dead in this minor", whether the promotion was traced or untraced.untracedgate. Dead objects in a traced promotion are left to the old generation, and the traced test below shows the next full collection frees them.map/store.rs), Set, Error diagnostics, lazy JSON tapes and the address-keyed side-table prune, through the existing from-space helper. The comment atgc/copying.rs:1205points at it.Tests
test-files/test_gap_map_store_untraced_promotion.ts: four cohorts of 160k object keys, each dropping the last. It matches Node (checksum 13419760 iterated 600319825), and before the fix it crashes 3/3.an_untraced_promotion_keeps_the_store_of_a_live_map:a_traced_promotion_keeps_the_live_map_and_reclaims_the_dead_one: in the traced path, the dead Map is still freed (at the next full collection).map_store.rstests now use a per-thread free counter, so they are safe in parallel.map_store_survives_tenured_evacuation_sweeps_and_exit_walkandmap_index_external_bytes_balance_…used to fail with 8 test threads; they now pass.Verification
cargo test --release -p perry-runtime -- --test-threads=1: 5221 passed, 0 failed. Main has 5219; the 2 extra are the new tests.map promote in_place copying set, with 1 and with 8 threads, 3 runs each: all pass exceptic_slow::an_unresolved_cache_slot_is_never_dereferenced, which also fails on main in debug builds only.cargo fmt --all -- --checkis clean.