ReviewOS

zig-utils/zig-js

Runtime: reject BigInt primitives as constructor prototype objects

#825
Closed chris opened this 9 days ago ·
9 days ago

Parent #465; related #823. Reproduced on pushed e24c4fa: function NewTarget() {}; NewTarget.prototype = 1n; Object.getPrototypeOf(Reflect.construct(TypeError, [], NewTarget)) !== TypeError.prototype. Node 24.18.0 passes the correct identity assertion; the local forced-tier witness fails in the tree walker. ctorRealmIntrinsicProto rejects the internal Symbol representation but accepts the internal BigInt cell as a JavaScript Object. GetPrototypeFromConstructor must distinguish ECMAScript objects from all internal primitive cells and select the exact newTarget realm intrinsic for primitive prototypes. Audit related prototype selectors, preserve one observable prototype get and abrupt completion, and add bound/proxy/cross-realm and forced-tier regression coverage. No mutable-name fallback or coercion workaround.

9 days ago

Expanded baseline is recorded: 90/90 reference probes pass in Node 24.18.0; the engine passes 28/90 in automatic mode and 28/90 forced tree/bytecode pairs. Coverage includes 28 constructor families with primitive BigInt prototypes, boxed-BigInt positive controls and foreign NewTarget realms, three dynamic function kinds, ordinary construction, one observable prototype get, and revocation during that get. No #825 implementation has been mixed into the #823/#824/#826 changes. The remaining work is constructor-prototype selection and exact realm fallback, not coercion of BigInt into an object.

9 days ago

The initial prototype-type patch exposed a separate required-bytecode path: ordinary new N() used the lazy prototype installer, accepting BigInt cells (and potentially replacing other primitive prototype values) instead of GetPrototypeFromConstructor. The working fix now routes that instance allocation through the semantic helper, without changing VM activation/lifecycle handling.

The expanded test now passes 94 programs in both forced tree-walker and required-bytecode modes under unsuppressed ReleaseSafe TSan: 1/1 test, zero failures/leaks, 3610ms. It covers 28 constructor families, boxed BigInt controls, foreign NewTarget, dynamic function kinds, all seven primitive prototypes, bound/proxy construction, one getter, and revocation during that getter. Node validates the reference cases.

This is still UNCOMMITTED and incomplete: Temporal realm fallback (beyond the type check), private intrinsic identity after public replacement, and moving-callback ownership/extended verification remain. #824 has a separate staged snapshot and full-unit run; this patch is not part of that commit.

9 days ago

Post-unit before/after execution is now recorded against the exact newly pushed #824 baseline (8e1e441): the existing 90 local witnesses improve automatic 28/90 -> 90/90 and forced execution pairs 28/90 -> 90/90. The extra four programs remain covered by the 94-program TSan unit, not that 90-witness script. These are local diagnostic witnesses, not a claim of test262 corpus flips.

The outstanding Temporal/intrinsic-retention/moving-GC scope above is unchanged; #825 remains uncommitted.

9 days ago

The remaining implementation now retains named prototype identities during unpublished realm bootstrap and adds a separate traced/relocated native [[Realm]] edge; GetFunctionRealm no longer casts arbitrary host private_data to Environment. It also handles all eight Temporal constructors (including Duration), and roots Function/dynamic-function results across prototype getters. The expanded seven multi-case reference programs pass Node v24.18.0 with experimental --harmony-temporal; exact managed/non-managed GC and moving-getter tests are building under unsuppressed ReleaseSafe TSan. This is still uncommitted work, not completion evidence. The first compilation exposed two test/bootstrap issues, now corrected; no test result or corpus gain is claimed until the corrected runs finish.

9 days ago

Landed and pushed as e35d4be1 — fix(runtime): retain constructor prototype realms (#825).

Verification on the exact committed six-file snapshot:

  • native Debug unit suite: 2,193 passed, 1 platform skip, 0 failed, 0 leaked (2,194 discovered; four shards)
  • unsuppressed ReleaseSafe TSan focus: 12 passed, 0 failed/leaked/races
  • selected constructor-related test262 scope: 18,031 pass / 2 pre-existing Function-realm failures before and after, so 0 corpus flips and no regression across 32 scored subtrees
  • local selector witnesses: 28/90 -> 90/90 in automatic and forced execution
  • extended realm witnesses: 2/10 -> 10/10 in automatic and forced execution
  • public C, Home public/private, Bun private, and private JSType ABI audits passed

The implementation captures realm-owned identities before publication, traces/relocates explicit native [[Realm]] edges, follows bound/proxy/closure GetFunctionRealm paths iteratively, and rejects internal Symbol/BigInt primitive cells without rejecting boxed objects. It preserves one observable prototype read and abrupt completion. CI for the pushed commit is now the remaining closure gate.

9 days ago

Terminal descendant-main verification is now complete: CI run 33312141595 on f4f00803 completed successfully with all 56 jobs terminal and no failed/cancelled jobs. This run contains the landed #825 implementation and the subsequent integration history. Closing the issue as completed; any newly reproduced defect should retain its own exact witness rather than reopening this verified scope.

Sign in to comment on this issue.