Skip to content

Treat "NaN" as a canonical numeric index string - #1643

Open
andreasrosdal wants to merge 3 commits into
quickjs-ng:masterfrom
nordstjernen-web:fix-canonical-numeric-index-nan
Open

Treat "NaN" as a canonical numeric index string#1643
andreasrosdal wants to merge 3 commits into
quickjs-ng:masterfrom
nordstjernen-web:fix-canonical-numeric-index-nan

Conversation

@andreasrosdal

Copy link
Copy Markdown
Contributor

JS_AtomIsNumericIndex1() short-circuits on the first character and only lets through digits, - and "Infinity", so the string "NaN" never reaches the ToNumber/ToString round-trip that implements CanonicalNumericIndexString. An XXX comment noted this.

CanonicalNumericIndexString("NaN") is NaN, not undefined, so on an integer-indexed exotic object "NaN" is an out-of-bounds index rather than a regular property. Before this change:

const ta = new Int8Array(4);
ta.NaN = 1;
ta.NaN                                         // 1, expected undefined
"NaN" in ta                                    // true, expected false
Object.getOwnPropertyNames(ta)                 // includes "NaN"
Object.defineProperty(ta, "NaN", {value: 7})   // expected TypeError

"Infinity" already behaved correctly; "NaN" is now handled the same way. "-NaN" is still rejected, because it is not the result of ToString(NaN).

Verified against test/built-ins/TypedArray + TypedArrayConstructors (43034 tests): unchanged, 38 pre-existing failures before and after.

🤖 Generated with Claude Code

https://claude.ai/code/session_014mv33YvfHz7t9mmkituBnn


Generated by Claude Code

claude added 3 commits August 6, 2026 17:08
JS_AtomIsNumericIndex1() short-circuits on the first character and only
lets through digits, '-' and "Infinity", so the string "NaN" never reaches
the ToNumber/ToString round-trip that implements CanonicalNumericIndexString.
An XXX comment noted this.

CanonicalNumericIndexString("NaN") is NaN, not undefined, so on an
integer-indexed exotic object "NaN" is an out-of-bounds index rather than a
regular property. Before this change:

    const ta = new Int8Array(4);
    ta.NaN = 1;
    ta.NaN                                    // 1, expected undefined
    "NaN" in ta                               // true, expected false
    Object.getOwnPropertyNames(ta)            // includes "NaN"
    Object.defineProperty(ta, "NaN", {value: 7})   // expected TypeError

"Infinity" already behaved correctly; "NaN" is now handled the same way.
"-NaN" is still rejected, because it is not the result of ToString(NaN).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mv33YvfHz7t9mmkituBnn
Checks all four integer-indexed exotic operations ([[Get]], [[HasProperty]],
[[Set]], [[DefineOwnProperty]]) plus [[Delete]] against a table of canonical
numeric index strings and of lookalikes that are not canonical, so the
prototype chain shortcut is exercised in both directions. Also pins that
ordinary objects, arrays, strings and ArrayBuffers keep "NaN" as a normal
property.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6eRbuuuCujKgQkrHgvMrc
An integer index that is out of bounds is not a property, so [[Set]] drops
the write and reports success. OP_put_ref_value relies on JS_PROP_NO_ADD to
notice that a `with` binding disappeared between the reference being taken
and the store, and the integer-indexed path returned before that check ever
ran, so the store silently succeeded instead of raising the ReferenceError
that SetMutableBinding step 3 calls for.

This was already reachable through Infinity, -0 and the rest; recognising
"NaN" as a canonical numeric index string just adds one more spelling, and
turns test262's set-mutable-binding-binding-deleted-with-typed-array-in-
proto-chain-strict-mode from passing by accident into failing. Check
JS_PROP_NO_ADD before the index is dropped, which fixes both spellings, and
drop the non-strict half of that pair from the expected failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6eRbuuuCujKgQkrHgvMrc
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.

2 participants