fix(codegen): root the URLSearchParams receiver across the name lowering - #7462
Merged
Conversation
added 2 commits
August 5, 2026 17:54
Six arms held a raw heap pointer across arbitrary user code. Same shape as #7453, found by scanning url_main.rs for a raw pointer bound before a lower_expr and used after it, then confirmed in emitted IR: %r22 = and i64 %r21, 281474976710655 ; p_ptr, raw heap pointer %r23 = call double @perry_fn_sp_root_ts__mk() ; user call, can collect %r24 = call i64 @js_url_search_params_get(i64 %r22, double %r23) Moving the unbox below the lowering would not fix it: p_v is the same pointer with a NaN-box tag on it, and a tagged pointer in an SSA register is exactly as invisible to the collector. Both operands are now lowered through lower_exprs_rooted and the receiver is unboxed from the RELOADED value: %r22 = call i32 @js_gc_temp_root_push(i64 %r21) ; root before %r23 = call double @perry_fn_sp_root_ts__mk() %r24 = call i64 @js_gc_temp_root_get(i32 %r22) ; re-read after %r26 = and i64 %r24, 281474976710655 ; unbox the reload %r27 = call i64 @js_url_search_params_get(i64 %r26, double %r23) call void @js_gc_temp_root_truncate(i32 %r22) ; release after use Arms: Get, Has, Set, Append, Delete, GetAll. The guard is released after the consuming call, not before -- the consumer allocates while reading these values. An earlier draft bound it to _operand_guard, which compiled clean and never emitted the truncate; in a loop that grows the temp-root stack without bound. 12/12 URL + URLSearchParams gap tests byte-identical to node; repro clean under PERRY_GC_HEAP_LIMIT=8 PERRY_GC_FORCE_EVACUATE=1.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR updates six ChangesURLSearchParams GC safety
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: ✨ 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 |
proggeramlug
added a commit
that referenced
this pull request
Aug 5, 2026
…both paths (#7463) * fix(codegen): root the third URLSearchParams operand, and release on both paths Corrects two defects in #7462. INCOMPLETE. Has/Set/Append/Delete take a third operand, and #7462 rooted only params+name -- so `value` still lowered AFTER the receiver was unboxed, leaving p_ptr and n_v crossing exactly the window the change was meant to close. All operands are now lowered together, `value` included when present. LEAKED. The automated release placement in #7462 landed inside Delete's `else` branch only, so the with-value path pushed two temp roots per execution and never truncated them -- unbounded growth in a loop. It compiled with no warning, which is why the arms are now audited programmatically for a top-level release rather than by reading. All six arms verified: one release each, at arm top level, reachable on every path. 12/12 URL + URLSearchParams gap tests byte-identical to node. A three-operand repro (set/append/has/delete, each argument a fresh allocating call) matches node and is clean under PERRY_GC_HEAP_LIMIT=8 PERRY_GC_FORCE_EVACUATE=1. * docs: changelog fragment for 7463 --------- Co-authored-by: Ralph Küpper <ralph@skelpo.com>
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.
Six more sites of #7453's shape, in the
URLSearchParamsfamily.Confirmed in IR, not inferred
p_ptris a raw heap pointer held across a full user function call.Moving the unbox below the lowering would not fix it —
p_vis the same pointer with a NaN-box tag on it, and a tagged pointer in an SSA register is exactly as invisible to the collector as an untagged one. That is worth stating because it is the obvious "fix" and it is wrong.Both operands now go through
lower_exprs_rooted, and the receiver is unboxed from the reloaded value:Arms:
Get,Has,Set,Append,Delete,GetAll.One thing I got wrong first
An earlier draft bound the guard to
_operand_guard. That compiled clean with no warnings and never emittedjs_gc_temp_root_truncate— so every execution of these arms would push two temp roots and never pop them, growing the stack without bound in a loop. The release has to be placed after the consuming call (the consumer allocates while reading these values), and "it compiles" was not evidence that it was.Verification
PERRY_GC_HEAP_LIMIT=8 PERRY_GC_FORCE_EVACUATE=1cargo fmt --checkcleanRemaining
The scan found 11 sites of this shape in
url_main.rs; these are the six uniformparams + namearms. The other five (UrlSetHref's value lowering, and three arms where the receiver is lowered second) have different shapes and are left for a follow-up rather than being swept in with a mechanical edit.Summary by CodeRabbit
URLSearchParamsoperations, including getting, checking, setting, appending, deleting, and retrieving all values.