[3] DFG MapIterationEntryKey Type Confusion
Severity: Critical | Component: JSC DFG JIT — DFGNodeType.h | 3f6f783
Rated Critical because the observable effect is a DFG type confusion where object keys are misrepresented with integer semantics, and the included test case demonstrates a near-complete exploitation sequence — GC-assisted object aliasing via heap spray — projected with confidence 0.88 from the single-token root cause and the PoC-grade regression test.
MapIterationEntryKey returns arbitrary JSValues (map keys can be any type), so it should be declared with NodeResultJS to match MapIterationEntryValue.
Source/JavaScriptCore/dfg/DFGNodeType.h
macro(MapIterationEntry, NodeResultJS) \
- macro(MapIterationEntryKey, NodeResultInt32) \
+ macro(MapIterationEntryKey, NodeResultJS) \
macro(MapIterationEntryValue, NodeResultJS) \
JSTests/stress/map-forEach.js
+ function inlinee(value, key) {
+ object.key = key;
+ }
+
+ for (let i = 0; i < 200; i++) {
+ map.forEach(inlinee);
+ }
+
+ for (let i = 0; i < 100; i++) {
+ startScan();
+ (new Map([[{0: 1.1}, 1]])).forEach(inlinee);
+ const spray = [];
+ for (let j = 0; j < 1000; j++) {
+ spray.push({0: 2.2});
+ }
+ if (object.key[0] === 2.2) {
+ throw new Error("bad");
+ }
+ }
Incorrect DFG node result-type declaration causing the JIT to speculate integer representation for an arbitrary-typed JSValue output.
Patch Details
The fix is a single-token change in the FOR_EACH_DFG_OP macro table in DFGNodeType.h: MapIterationEntryKey is changed from NodeResultInt32 to NodeResultJS. The companion regression test demonstrates the bug by using Map.forEach with object keys, triggering DFG compilation via a hot loop, then heap-spraying to verify that the type confusion produces observable object aliasing.
Background
JSC's DFG JIT uses a node type table (FOR_EACH_DFG_OP macro) where each IR node declares its result type via flags like NodeResultInt32, NodeResultJS, NodeResultDouble. These flags drive prediction propagation, register allocation, representation selection (boxed vs. unboxed), and write barrier generation throughout the DFG pipeline. NodeResultInt32 tells the compiler the node always produces an unboxed 32-bit integer, which affects how downstream nodes consume the value — the tag is stripped, and the raw 32-bit payload is operated on directly.
JSC uses NaN-boxing on 64-bit platforms to encode JSValues: object pointers, doubles, and integers all share a 64-bit representation distinguished by tag bits. When the DFG compiles code under int32 speculation, it strips the tag and operates on the raw 32-bit payload, re-tagging when a boxed JSValue is needed downstream.
JavaScript Maps can have keys of any type — objects, strings, numbers, symbols. The Map.prototype.forEach method iterates over all entries, passing (value, key, map) to the callback. When the DFG inlines such a callback, it emits MapIterationEntryKey and MapIterationEntryValue nodes to extract the key and value from each entry. MapIterationEntryValue was already correctly declared as NodeResultJS.
Analysis
The root cause is a single wrong flag in the DFG node type table. MapIterationEntryKey was declared with NodeResultInt32, indicating that its result is always an unboxed 32-bit integer. In reality, Map keys are arbitrary JSValues. When the DFG compiler processes a Map.forEach callback and encounters the iteration key, it uses the NodeResultInt32 declaration to drive prediction propagation and code generation. For a key that is actually an object pointer (a 64-bit tagged JSValue in NaN-boxing), the DFG generates code that treats the result with integer representation semantics. This misrepresentation causes the object pointer to be handled with wrong type assumptions through the DFG pipeline — the value is likely truncated, mis-tagged, or lacks proper GC write barriers. If the GC does not properly trace the reference (because the wrong representation hides the pointer from the collector), the original key object could be collected while a stale pointer remains, leading to a use-after-free.
The asymmetry between MapIterationEntryKey (Int32) and MapIterationEntryValue (JS) strongly suggests a copy-paste error or an assumption that map keys are integer indices rather than arbitrary values. The FOR_EACH_DFG_OP table is the single source of truth for node result types across the entire DFG pipeline, making any error in this table automatically propagate through prediction, speculation, register allocation, and write barrier generation.
Aaa Aaaaaaaa Aaaa Aaaa Aa Aaaaaaaaaaa a Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaa Aaaa Aaaaaaaaa Aaa Aaaa Aaaaaa Aaa Aaaaaaaa Aaa
Aa Aaaaaa a Aaa Aaaa Aa Aaaaaa Aaa Aaaaa Aaaaaaa
Aa Aaaaaa a Aaaaaaaaa Aaaaaaaa Aaaa Aaaaaa Aaa Aaa Aaaa a Aaaaaaaa Aaaaaaaaaaaa a Aaaaaa
Aa Aaa Aaa Aaaaaaaa Aa a Aaa Aaaa Aaaa Aaaaaaaaaaa Aa Aaaaaaa Aaa Aaaaaaaaaaaa Aaa Aaa Aaaaaaaaaa Aaaa Aaa Aaa Aa Aaaaa Aaa Aa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaa
Aa Aaaaa Aaa Aaaaaaaaaaaa Aaaaaa Aaaaaaaaa Aaaaa a Aaa Aaaaaaaaaaaa Aaaa Aaaaaaaaaaaaa Aaa Aaaaaa Aaa Aaaa Aaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaaaaa Aaaaaaa Aaaa Aaaaaaaaaaaa
Aa Aaaaaaa Aa Aaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaa Aaa Aaaaaa Aa Aaa Aaaaaaaa Aaaaaa Aaa Aa Aaa Aaaaa Aaaaaaaaaaaaaaa Aa Aa Aaaaaaaaaa
Aa Aaaaaaaaaa Aaaa Aaaaaaa Aa a Aaaaa Aaaaa Aaaaa Aaaaaa Aa Aaaaaaa Aaa Aaaaa Aaaaaaa
Aa Aaaaaa Aaaaaaaaaaaaaaa a Aa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaa a Aaaaaaa Aaaaaaa Aaaaaaaa Aaaaaa Aaaaaaaa Aaaa Aaa Aaaaaaa Aaaaa Aaaaaa Aaaaaaaaaa Aaaa Aaaaaaaaa Aaa Aaaaaa Aaaaaaaaa
Aaa Aaaaaaa Aaaa Aa Aaa Aaaaaaaaaa Aa Aaaaaaaaaa Aa Aaaaaaa Aaa Aaaaaaaaaaa Aaa Aaaa Aa Aaa Aaaaaaaaaaa Aaaaaaaaa Aaa Aaaa Aaaa Aaaaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaa Aa Aaaaa Aaaaaaa Aaaaaaaaaaa Aaa Aaaaa Aaaa Aaaaaaaaa Aaaa Aaaaaaa Aaa Aaaaaaaaa Aa Aaaaaaa Aaaaa Aaaaaa
Aaaa Aa Aaaaaaaaaaa Aaaa Aaa Aaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaa Aaaaa Aaa Aaaa Aaaa Aaaaaaaaaaaa a Aaaaaaaa Aaaaaaa Aaaaaaaa Aaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaa Aaa Aaaaaa Aa a Aaaaaaaaa Aaaaaa Aaaaa Aaaaaaa Aaa Aaaaaaaa Aaaaa Aaaaa Aaaa Aaaaaaaaaaaa Aaaaaaaaa a Aaaa Aaaaaaaaa Aaaaaaaaa Aaaaa Aaaaaaaaaaaa Aaaaaa Aa Aa Aaaaaaaaaaaaaaa Aaaaaaa Aaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaa a Aaaaaaaa Aaaaaaa Aaaaaa Aaaaa Aa Aaaaaaaa Aaa Aaaa Aaaaaa Aaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaa Aaaa Aaaaaaaa Aaaaaa Aaaaaa Aaaaaaaaaa Aaaaaa Aaa Aaaaaaaa Aaaaaaaa Aaa Aaa Aaa Aaaaaaaaa Aaaa Aaaa Aaaaaaa Aaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaa Aa Aaaa Aa Aaaaaaaa Aa Aaaaaa Aaaaaaaa Aaaaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaa Aaaa Aaaaaaaaaaaa Aaaa Aaaaaaaaa Aaaaaaa Aaaa Aaaaaaaaa Aaa Aaaa Aaaa Aaaaaaaaaaaa Aaaa Aaaa Aaaaaaaa Aaa Aaaaaaaa Aaa Aaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaa Aaaaaaa a Aaa Aaa Aaaaaaa Aaaa Aaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaaa Aa Aaaaaa
Audit directions
a Aaaaaaaa Aaa Aaaa Aaaaaaaaaaa Aaaaaaaaaaaa Aaaa Aaaaaaaa Aa Aaaaaa Aaaa Aaaa Aaaaaaaa Aaaa Aaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaa Aaaaaaa Aaa Aaaa Aa Aaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaa Aaaa Aaa Aaaa Aaaaa Aa Aaaa Aaaa Aaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaa Aaaa Aaaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaaaaaa a Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaa Aaaa Aaaaaaaa Aaaaaaaaa Aaaaaa Aaa Aaaaa Aaaaaa
a Aaaaaaaa Aaaaaaaaaa Aaaa Aaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaa Aa a Aaaa Aaaaaaaaa Aa a Aaaaaa Aaaaaa Aa a Aaaa Aaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaa Aaaaaaaaa Aaaaa Aaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaaaaaaaa Aaaaaaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaaaaaa Aaaaaa Aaaaa Aaa Aaaaaa Aaa a Aaaa Aaaaaaaaaaa Aaaaaa Aaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaaa Aaaaa Aaaaaaa Aaaaaa Aaaaaa Aaaaaaa Aaa Aaaaaaaaa Aaaaaaaaaa
a Aaaaaaaa Aaa Aaaa Aaaaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaa Aaaaaa Aaaaaaaaaaa Aaaa Aaa Aaa Aaaaaaaaaa a Aaaaaa Aaaa Aaaaaaa Aaaaaaa Aaa a Aaaaa Aaaa Aa Aaaaaaaa Aa Aaaaaa Aaaaaaaa Aaa Aa Aaa Aaa Aaaaaaaa Aaaaa Aaa Aaaaaaaaaa Aaaaaa Aaa Aaaaaa Aaaaaaaa Aaa Aaaaaaaaaa Aaaaa a Aaaaa Aaaaaaa Aaaaaaaa Aaaaa Aaaaa Aaa Aaaaa Aaaaa Aaaa Aaaaaaaaaaa Aaaaa Aaaaa Aa Aaaaaa Aaaaaaa Aa Aa Aaaa Aa a Aaaaaaaaaaa Aaaaaaaa Aa Aaaaaa Aaaaaaa a Aaaaa Aaaaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaa Aaaaaaaa Aaaa Aa Aaaaa Aaaaaaaa Aaa Aaaaaa Aaaaaaaa
Aaaaaaaaa Aaaa Aaaaaaa a Aaaa Aa Aaa Aaaaa Aaaaaaaaa Aa Aaaaa Aaa Aaaaa Aaaaaa Aaaa Aaaaaa Aaa Aa Aa Aaaa Aaa Aaaaaaaaaa Aaa Aaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaaaaa Aaa Aaaaaaaaaaa a Aaa Aaaaaaaa Aaaa Aaa Aaaa Aaaa Aaa Aaaaaaaaaa Aaa Aaaaaaaa Aaaaaaaaa Aaa Aaaa Aaaa Aaaaaaaaa Aaa Aaa Aaaaaaaaaaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaaaaa Aa Aaa Aaaaaaaa Aaaaaaaaaa Aaaaa