fix(gc): pin long-lived and malloc-resident objects without the space classifier (#7650) - #7655
Conversation
… classifier #7650 routed every GC_FLAG_PINNED write through gc::pin_object, which reaches arena::classify_heap_space. That new edge kept a reference chain alive that -Wl,-dead_strip had been removing, and five perry-ext-* crates stopped linking: Undefined symbols for architecture arm64: _js_blob_new, _js_fetch_with_options, _js_fetch_notify_signal_aborted perry-ext-{pdf,lru-cache,node-forge,mongodb,http} all failed. Bisected: the commit before #7650 builds them clean, #7650 does not, and reverting just the two perry-runtime call sites restores the link. perry-stdlib's async_bridge keeps pin_object -- its promises really are Eden-resident and must arm the latch. The two reverted sites are documented by #7650 itself as long-lived and malloc-resident, so they never needed the classifier. pin_object_non_young does the flag write directly, debug_asserts the claim, and has a unit test asserting it for each real call site plus a control proving the predicate is not vacuously false. Not visible per-PR: cargo-test scopes to the changed crates' reverse-dependency closure, and the full workspace runs on tags and nightly only. Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
|
Warning Review limit reached
Next review available in: 48 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (8)
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 |
It was written before the PR number was known and collided with #7653's native-root-coverage fragment. Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
fix(gc): pin long-lived and malloc-resident objects without the space classifier (#7650 follow-up).#7650 routed every
GC_FLAG_PINNEDwrite throughgc::pin_object, which reachesarena::classify_heap_space. That new edge kept a reference chain alive that-Wl,-dead_striphad been removing, and fiveperry-ext-*crates stoppedlinking:
perry-ext-{pdf,lru-cache,node-forge,mongodb,http}. They link a feature-strippedruntime through
perry-ffi'sruntime-link, so those thunks have no definitionand only survived because the stripper removed them.
Bisected rather than guessed: the commit before #7650 builds all five clean,
#7650 does not, and reverting only the two
perry-runtimecall sitesrestores the link.
perry-stdlib'sasync_bridgekeepspin_object— itsjs_promise_new()promises really are Eden-resident and must arm the young-pinlatch.
pin_object_non_youngdoes the flag write directly for the sites #7650's owncomments already document as long-lived (
string/format.rs, the interned formatbuffer) and malloc-resident (
thread.rs, the spawn promise and its handle) —they never needed the classifier. Making
pin_objectconservative instead(arming for any
GC_FLAG_ARENAobject) would also remove the edge, but it wouldarm on exactly these long-lived pins and throw away the preflight skip #7645
bought.
The claim is checked, not asserted.
debug_assertcatches a young object intest builds, and
pin_object_non_young_call_sites_are_never_young(
gc/tests/copying/latch.rs) asserts non-youngness for each real call site plusa control proving the predicate is not vacuously false for everything. Sabotage:
forcing the predicate false reddens the control (0 compile errors, test binary
reached).
Why no gate caught it.
cargo-testscopes per-PR runs to the changed crates'reverse-dependency closure (
scripts/ci_test_scope.py); the full workspace runson tags and nightly only.
perry-ext-*is outside the closure of aperry-runtimeGC change, so this could only have surfaced at the next tag.Found by running
cargo test --release --workspaceby hand againstmain.