Skip to content

codegen: js_box_set/js_box_get emitted with undef box-pointer operand (mutable-capture box alloc elided on taken path) — source bug behind #4898 #4926

@proggeramlug

Description

@proggeramlug

Follow-up to #4898 / PR #4902 (deferred there by design).

Summary

PR #4902 added a runtime gate (is_registered_box_ptr) so js_box_set/js_box_get silently skip pointers that were never minted by js_box_alloc. That makes the react-reconciler SIGBUS correctness-safe, but the source bug is still present: codegen can emit a js_box_set call whose box-pointer operand is undef/poison — a mutable-capture box whose allocation was elided on the taken path while the store survived.

Evidence (from the #4898 deep-triage)

  • Faulting site (pre-fix(runtime): reject unregistered box pointers in js_box_set/get (#4898) #4902): str d0,[x0] inside js_box_set with x0 = &"object_get_by_name_guard" — a read-only __TEXT.__cstring typed-feedback guard-name constant (chore: triage dead-code warnings (fields, variants, constants, dead assignments) #854 register_site arg). The module IR never stores into any guard global (verified across all --trace llvm modules; all 8292 guard uses in the react-reconciler production module are register_site args). The stray pointer is a pure optimizer/regalloc artifact of an undef operand: regalloc fills the register with whatever happens to be live, and react-reconciler's single giant minified module.exports = function($$$config){…} emits ~2500 register_site calls in one function, so a guard cstring pointer is what's live.
  • An undef operand reaching a call means LLVM proved the box-pointer SSA value undefined on some path — i.e. a path exists where the capture box was never allocated/stored but js_box_set for that capture is still reachable.

Repro

import createReconciler from 'react-reconciler';
console.log('reached');

(test-files/ink-sandbox/rr_min.tsx). Pre-#4902 this SIGBUSed at module init. Post-#4902 the bad call is silently skipped — so the localization handle is the rejection itself: an env-gated diagnostic in the is_registered_box_ptr failure arm (print/abort) should fire on this repro and identify the first offending site.

Suggested attack

  1. Add a temporary PERRY_BOX_DIAG=1 (or reuse PERRY_GC_DIAG) print/trap in the js_box_set/js_box_get unregistered-pointer arm to confirm the stray call still occurs on main and capture a backtrace.
  2. Audit closure-conversion / codegen paths where a capture's box alloc is conditional (lazy alloc, dominance assumption) while the corresponding js_box_set is emitted unconditionally — likely a dominance bug: alloc emitted in a block that doesn't dominate the store.
  3. Fix so every emitted js_box_set/js_box_get operand is dominated by its js_box_alloc (or the alloc is hoisted), then verify the diagnostic no longer fires on the react-reconciler repro.

Likely same root family as #2564 (captured Object.assign alias → HostRoot hang).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions