[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;
Patch Details
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.
Background
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.
Analysis
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.
Aaa Aaaaaaaaa Aaaaaa Aaaaaaaaaaa Aaaaaaaa Aaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaa Aaaaaa Aaa Aaaa Aaaaaaa Aa a Aaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaa Aaaaaaaaaaa Aaaaaaaa a a Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaa Aaa Aaaaaaaaaa Aaaa Aaaaa Aa Aaaaaaaaaaaaa Aaa Aaaaa Aaaaa Aaaaaaa Aaaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaa Aaaaa Aaa Aaaaa Aaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaa a Aaaaa Aaaaa Aa Aaaaaaaa Aa Aaa Aaaaaaaa Aaa Aaaaaaaaaaaaaa Aa Aaaaaaaaaaa Aa Aaa Aaaaaaaa Aaa Aaaaaaaaaaaaaa Aaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaaaaa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaa Aaaaaaaa Aa Aaaaa Aaaaaa Aaaaa Aaa Aaaa Aaaaaaa
🔒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
Audit directions
a Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaa Aaa Aa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aa Aaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaa Aaaaaa Aaaaaaa Aaaaaaaaaaaa
a Aaaaaaa Aa Aaaaaaa Aaaaaaa Aaaaaaa a Aaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaa Aaaaa Aaaaaaa Aaaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaaaaaaaa Aaaaaa Aaa Aaaaaa
a Aaaaaaaaaaaaa Aaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaa Aaaa Aaaaaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa Aaaaaa
a Aaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaaaa Aaaaa Aaaaa Aa Aaaaaa Aaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaa Aaa Aaaa Aaaaa Aaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaaaa
🔒Four reusable audit patterns for DFG CSE-key soundness, with specific starting files in the JSC tree for variant discovery.
Subscribe to read more