Skip to content

fix(gc): root the callee across the instance allocation in new - #7391

Merged
proggeramlug merged 2 commits into
mainfrom
fix/7341-new-function-construct
Aug 4, 2026
Merged

fix(gc): root the callee across the instance allocation in new#7391
proggeramlug merged 2 commits into
mainfrom
fix/7341-new-function-construct

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Closes another #7341 catch — and this one was silently returning wrong answers, not just crashing under quarantine.

The bug

js_new_function_construct allocates the instance, then decodes the closure out of func_value — computed before that allocation — and reads CLOSURE_MAGIC off it via is_closure_ptr. An evacuating minor inside the allocation moves the closure, so the decode names from-space.

The disassembly matches the source predicate exactly:

+5208:  bl  js_object_alloc_with_parent    ; allocates
+5304:  ldr w8, [x24, #0xc]                ; faults
+5308:  cmp w8, #0x434c                    ; "CL" — CLOSURE_MAGIC

Why it matters beyond the crash

Without the quarantine this is quiet. The magic check simply fails, so the user-prototype link is skipped and the instance gets the wrong [[Prototype]]foo.prototype = new Array(1,2,3) not taking effect, with no crash and no diagnostic. That is the failure mode the quarantine exists to surface: evacuation copies rather than zeroes, so a stale address still holds plausible bytes.

Sibling

js_new_function_construct_with_new_target has the identical shape with nt in place of func_value, consumed by constructor_prototype_bits on the line after the same allocation. Fixed as the same defect — and the code comment says plainly that it is not independently reproduced, since only the plain-new path has a measured fault.

A process note worth keeping

My first attempt placed the republish after the use — it landed inside the if, past the point where fp was already derived from the stale value. Source looked right; the disassembly showed the deref at +5404 still preceding the handle read at +5420. Second attempt puts it immediately after the allocation. A fix that reads correctly and disassembles wrong is still broken.

Verification

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where constructing objects after garbage collection could use stale constructor or target information.
    • Ensured objects created with new and Reflect.construct retain the correct prototype, including user-assigned prototypes.
    • Prevented silent construction errors when allocation triggers memory evacuation.

Ralph Küpper added 2 commits August 4, 2026 20:50
js_new_function_construct allocates the instance, then decodes the
closure pointer out of `func_value` -- a value computed BEFORE that
allocation -- and reads CLOSURE_MAGIC off it via is_closure_ptr. The
allocation can drive an evacuating minor, so the decode names from-space.

The disassembly is unambiguous:

    +5208:  bl  js_object_alloc_with_parent    ; allocates
    +5304:  ldr w8, [x24, #0xc]                ; faults
    +5308:  cmp w8, #0x434c                    ; "CL" -- CLOSURE_MAGIC

Without the quarantine this is QUIET rather than fatal: the magic check
simply fails, so the user-prototype link is skipped and the instance
silently gets the wrong [[Prototype]] -- `foo.prototype = new Array(1,2,3)`
not taking effect, with no crash and no diagnostic.

js_new_function_construct_with_new_target carries the identical shape with
`nt` in place of `func_value`, used by constructor_prototype_bits on the
line after the same allocation. Fixed too; noted in-code that it is not
independently reproduced.

test_gap_learned_inline_sizing is byte-identical to Node under from-space
quarantine (was SIGBUS). 47 class/proto/construct/new/reflect/inline gap
tests pass; the two that fail also fail on pristine main, and the unit
suite's 4 failures sit inside main's own 3/5/3 noise band (#7365).
@proggeramlug
proggeramlug merged commit e6535d4 into main Aug 4, 2026
0 of 15 checks passed
@proggeramlug
proggeramlug deleted the fix/7341-new-function-construct branch August 4, 2026 18:50
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c1b372b-f2ad-4d37-8628-037f3ed0ffe4

📥 Commits

Reviewing files that changed from the base of the PR and between e1762d8 and f310c76.

📒 Files selected for processing (2)
  • changelog.d/7391-new-construct-rooting.md
  • crates/perry-runtime/src/object/class_registry/construct.rs

📝 Walkthrough

Walkthrough

The construction paths now root constructor closure and newTarget values during allocation. They reload relocated values before prototype and closure inspection. The changelog records the stale-pointer fix and test results.

Changes

Constructor GC rooting

Layer / File(s) Summary
Root constructor values across allocation
crates/perry-runtime/src/object/class_registry/construct.rs, changelog.d/7391-new-construct-rooting.md
The ordinary and distinct-newTarget paths root values across allocation and reload their post-GC values before prototype or closure inspection. The changelog documents the affected paths and test results.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

  • PerryTS/perry#6983 — Addresses GC rooting and reloading of constructor-related values across allocation.
  • PerryTS/perry#6941 — Roots live NaN-boxed values across allocation-capable runtime operations.
  • PerryTS/perry#7192 — Addresses GC rooting across allocation-triggered collections in constructor paths.

Suggested reviewers: thehypnoo

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/7341-new-function-construct

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant