Skip to content

Fix ES2024 TypedArray accepting almost every kind of key - #2264

Open
alielmorsy wants to merge 1 commit into
meta:static_hfrom
alielmorsy:fix/typedarray-invalid-index-set
Open

alielmorsy wants to merge 1 commit into
meta:static_hfrom
alielmorsy:fix/typedarray-invalid-index-set

Conversation

@alielmorsy

@alielmorsy alielmorsy commented Oct 22, 2026 •

Copy link
Copy Markdown

Summary

Fix ES2024 TypedArray accepting almost every kind of key including strings, Floats,...etc. by intercepting the non-index canonical keys and ignoring writes to them.

A TypedArray handles every canonical numeric string key itself (ES2024 10.4.5, CanonicalNumericIndexString). Hermes treated keys such as "-1", "-0", "1.5", "4294967295", "NaN" and "Infinity" as ordinary property names, because they are not array indices, so a write created a real own property on the TypedArray.

Specifically:

  • Reject [[DefineOwnProperty]] for out-of-bounds or non-index canonical keys (throws TypeError via Object.defineProperty, returns false via Reflect.defineProperty).
  • Silently ignore writes (returns true) while still performing value conversion when the receiver is the TypedArray itself.
  • Stop [[Get]] and [[HasProperty]] at the TypedArray for numeric keys instead of walking the prototype chain (ES2024 10.4.5.2, 10.4.5.4), so a property on Object.prototype can no longer answer t[-1] or "5" in t.

Strings that only look numeric but are not canonical ("01", "+1", "1e3") remain ordinary properties.

Example

var t = new Int8Array(2);
t[-1] = 5;
t["1.5"] = 6;
t.NaN = 7;
print(JSON.stringify(Object.keys(t)));
Object.prototype[-2] = "from proto";
print(t[-2], "-2" in t);
try {
  Object.defineProperty(t, "-3", {value: 1});
} catch (e) {
  print(e.name);
}
Before After V8 (Node 26.11.1, V8 14.6)
Object.keys(t) ["0","1","-1","1.5","NaN"] ["0","1"] ["0","1"]
t[-2], "-2" in t from proto true undefined false undefined false
Object.defineProperty(t, "-3", ...) succeeds silently TypeError TypeError

Detailed Fix

Detecting the keys. Added two static helpers to implement CanonicalNumericIndexString (ES2024 7.1.21):

  • isCanonicalNumericKey(runtime, key) returns true for any Number key. For strings, it rounds through ToNumber and numberToString to see if the string survives unchanged. Handled "-0" as an edge case since ToString(-0) evaluates to "0".
  • isNonIndexCanonicalNumericKey(runtime, key) ensures the key is not an array index. Because TypedArray lengths use uint32_t, 0xFFFFFFFF can never be a valid integer index. An overload for SymbolID handles pinning the string in a Locals slot before delegating here.

Both guards start with vmisa<JSTypedArrayBase>, so non-TypedArray objects only pay for a cell-kind check without parsing strings.

[[Set]] (ES2024 10.4.5.5). In putComputedWithReceiver_RJS and putNamedWithReceiver_RJS, we now bail out before prototype lookup if the target is a TypedArray and the key is a non-index canonical numeric string. The setInvalidTypedArrayIndex helper returns true without writing. If the receiver is the TypedArray itself, it triggers setOwnIndexed(self, 0xFFFFFFFF, value). Since this index is always out of bounds, it simply executes the standard ToNumber/ToBigInt element conversion (preserving valueOf side effects and BigInt TypeErrors) without modifying the buffer.

[[DefineOwnProperty]] (ES2024 10.4.5.3).

  • defineOwnPropertyInternal now rejects non-index canonical keys on TypedArrays right before adding a named property.
  • In defineOwnComputedPrimitive, if an index key is missing (detached buffer or out of bounds), define now properly fails. Previously, value definitions fell back into setOwnIndexed and were silently dropped, while accessor definitions accidentally created named properties.

[[Get]] / [[HasProperty]] (ES2024 10.4.5.4, 10.4.5.2). Lookups on prototype chains now halt at a TypedArray for numeric keys:

  • In getComputedPrimitiveDescriptor, if an own lookup misses on a TypedArray, any canonical numeric key stops the traversal (propObj = nullptr). Lookups like t[5] past the array bound will no longer pull values off the prototype.
  • getNamedDescriptorUnsafe applies the same rule for named lookups like t.NaN or t.Infinity, both directly and when a TypedArray appears higher up the prototype chain.

Because these paths are shared, operations like in, Reflect.has, prototype accessors, and out-of-bounds writes avoid hitting prototype setters without needing separate guards.

Test Plan

Added regress-typedarray-canonical-numeric-keys.js and ran tests on (WSL ubuntu 22) and Windows MSVC 2022

@meta-cla meta-cla Bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Oct 22, 2026
@alielmorsy alielmorsy changed the title Fix ES2024 TypedArray accepting almost every kind of key including strings, Floats,...etc. by intercepting the non-index canonical keys and ignoring writes to them. Fix ES2024 TypedArray accepting almost every kind of key including strings, Floats,...etc. Oct 22, 2026
@alielmorsy alielmorsy changed the title Fix ES2024 TypedArray accepting almost every kind of key including strings, Floats,...etc. Fix ES2024 TypedArray accepting almost every kind of key Oct 22, 2026
…rings, Floats,...etc. by intercepting the non-index canonical keys and ignoring writes to them.

Specifically:
- Reject [[DefineOwnProperty]] for out-of-bounds or non-index canonical keys (throws TypeError via Object.defineProperty, returns false via Reflect.defineProperty).
- Silently ignore writes (returns true) while still performing value conversion when the receiver is the TypedArray itself.
@alielmorsy
alielmorsy force-pushed the fix/typedarray-invalid-index-set branch from 1abc2c1 to 239e01e Compare October 22, 2026 20:18

This branch has not been deployed

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

Labels

CLA Signed Do not delete this pull request or issue due to inactivity.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant