You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Hole-leak family: js_array_get_f64's Set/Map arm skips hole translation — typeof hole is "number", String(hole) is "NaN", console.table renders NaN cells #9462
An exhaustive audit of the if tag == A || tag == B { … } else { treat as C } fall-through shape (run for PR #9461) found six more live sites. Each was reproduced, not inferred. They are one family: a TAG_HOLE that escapes translation at its source, plus downstream ladders with no hole arm.
The leak source (fix this first)
array/indexing.rs:549 — the Set/Map arm of js_array_get_f64 returns a raw slot with no hole translation, unlike the array arm at :440. This is what makes the downstream sites reachable at all.
Downstream ladders with no hole arm
builtins/arithmetic.rs:778 — classify_value_typeof has no TAG_HOLE arm: typeof hole === "number" (node: "undefined").
value/to_string.rs:1357 — js_jsvalue_to_string renders a hole as "NaN" (node: "undefined").
builtins/table.rs:444,456 — console.table([[1,,3]]) renders the hole cell as NaN. The sibling primitives-only branch at :467 already has the TAG_HOLE skip; the two array-of-arrays branches were missed. Note a cell-only fix still will not match node — node omits the hole's column entirely, so the header derivation needs the same treatment.
builtins/table.rs:546 — const o={a:1,b:2}; delete o.a; console.table(o) prints b | NaN. Different mechanism: object_key_names drops tombstoned keys from a Vecwithout preserving slot indices, then indexes fields by compacted position. format_object_as_json and both console.rs sites iterate 0..key_count and continue on a non-string key — table.rs is the outlier.
Why this family keeps producing bugs
Tag ambiguity in perry is by design (0x7FFC is both undefined and TAG_HOLE; 0x7FFE both INT32 and class-ref), and tombstone deletes (#9331, default-on) made TAG_HOLE common in live data. Every value-decoding ladder written before that is a candidate. This family has now produced #9398 (SIGSEGV), #9415 (NaN holes / integer classes), #9409 (split("")), and these six.
Fix the leak source first, then check which downstream symptoms become unreachable — the typeof/String sites may still be reachable through other hole producers, so each needs its own repro: a .ts fixture byte-compared to node --experimental-strip-types, demonstrated failing on unfixed origin/main, covering typeof, String(), template interpolation, console.table on holey rows and tombstoned objects, and a Map-typed function parameter that keeps its fast path after .delete() (assert via the deopt counter, not timing).
Activity
fix(runtime): the hole-leak family — Set/Map raw reads, pop, typeof/S…