Parent: #493 Related: #521, #759
Problem
Interpreter.objectOwnKeysList uses three transient
std.AutoHashMapUnmanaged(usize, void) membership tables while merging
integer-index keys for String exotic objects, Arrays, and ordinary/host
objects.
Canonical array-index names are script-controlled. Zig's auto hash for
usize is Wyhash(0, asBytes(key)), so an attacker can precompute an
arbitrarily large family that lands in the same probe bucket and amplify
Object.keys, Reflect.ownKeys, JSON/property traversal, and every other
consumer of [[OwnPropertyKeys]].
The result is already sorted numerically after membership filtering, so a hash table is unnecessary.
Required design
- Collect all candidate canonical integer-index keys.
- Sort once by their numeric index as ECMA-262 requires.
- Collapse adjacent equal canonical indices in place.
- Preserve String exotic virtual indices, dense/sparse/accessor merging,
Array
lengthplacement, ordinary string insertion order, symbols, and host-hook overlap semantics exactly. - Remove the fixed-seed numeric membership tables and their scratch allocations.
- Do not add caps, input rejection, fallback seeds, linear duplicate scans, or semantic shortcuts.
This gives deterministic O(n log n) worst-case work and avoids secret state
for a surface whose required final order already pays for sorting.
Acceptance
- All three numeric own-key paths share one sort-and-deduplicate primitive.
- A deterministic family colliding under the removed default hash is returned once each in exact numeric order.
- Ordinary objects, Arrays, String exotic objects, sparse/accessor keys, and symbols retain exact own-key semantics.
- Focused Debug, ReleaseSafe, and TSan tests pass.
- Full sharded units, relevant Test262 ownKeys/Object.keys/JSON subtrees, threadfuzz, C API, and private ABI gates show no regressions.
- Commit and closure evidence link exact commands/results.