← All issues

[10] [JSC] StringAt should respect arrayMode in CSE

Severity: High | Component: JSC DFG JIT | 1f4e4ca

Rated High because the diff fixes an unsound CSE on String.prototype.at: the GCSE key omitted arrayMode, allowing the optimizer to merge an in-bounds (returns String) computation with an OOB (returns undefined) computation — a type confusion at JIT-IR level reachable from web JS.

StringAt fell through to StringCharAt's def(PureValue(node)) clause. charAt is type-stable (always returns a string, empty on OOB), but at returns either a string or undefined depending on bounds.

Source/JavaScriptCore/dfg/DFGClobberize.h

case StringAt:
+ def(PureValue(node, node->arrayMode().asWord()));
+ return;
case StringCharAt:
def(PureValue(node));
return;

StringAt gets its own case calling def(PureValue(node, node->arrayMode().asWord())), folding ArrayMode into the CSE key so nodes with different array modes are no longer merged.

CSE key omits a mode discriminator that controls the operation's return type, allowing the optimizer to merge two computations with incompatible output-type contracts.

clobberize() produces read/write/def summaries that drive CSE for pure nodes. PureValue is the CSE key for side-effect-free nodes; by default it hashes (opcode, child edges), but an extra discriminator can be folded in via PureValue(node, word). ArrayMode is the DFG's per-node specialisation of an indexed operation, derived from per-bytecode array profiles. String.prototype.at(i) returns the code unit string at i if in range and undefined otherwise — distinct from charAt, which returns the empty string for OOB.

Two s.at(i) calls in the same function can be specialised differently — one as String in-bounds, another as Generic/OOB-observing. With the shared PureValue(node) key omitting ArrayMode, CSE happily merged a mode-A StringAt with a mode-B StringAt using the same string/index inputs.

🔒

Explores how a missing discriminator in a JIT optimizer's deduplication key turns a benign-looking pure-value handler into a type-confusion primitive, and what downstream escalation would require.

Subscribe to read more

🔒

Four reusable audit patterns for DFG CSE-key soundness, with specific starting files in the JSC tree for variant discovery.

Subscribe to read more