Medium CVSS 7.5 webkit Type Confusion 🔧 Commit mapped

Overview

Medium
Severity
7.5
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected process crash
ComponentWebKit
Bug ClassType Confusion
Tracker308545
Fix commit392f508eef94 (WebKit/WebKit) +13/-0
CWECWE-119, CWE-120 (Buffer bounds error, Buffer overflow)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedYuhao Hu, Yuanming Lai, Chenggang Wu, and Zhe Wang
Disclosed2026-05-11

Background

OSR exit
On-stack replacement from optimized JIT code back to a lower tier when a speculation fails; sunk allocations must be materialized at that point.
PhantomNewArrayWithButterfly
A DFG representation of an array allocation the JIT elided (‘sank’); its concrete object and butterfly storage are only built if an OSR exit needs it.
operationPopulateObjectInOSR
The runtime helper that fills a materialized sunk object’s storage during OSR exit.
Unwritten slot / array hole
An element with no corresponding store; it must be initialized to the array hole (empty), not left as an uninitialized JSValue.

Root Cause Analysis

This fixes incorrect handling of unwritten array slots when a sunk allocation is materialized on OSR exit. Per the commit (‘Fix incorrect handling of unwritten slots in operationPopulateObjectInOSR for PhantomNewArrayWithButterfly’), the DFG/FTL can sink an array-with-butterfly allocation (represented as PhantomNewArrayWithButterfly) and only materialize it if an OSR exit requires the concrete object; operationPopulateObjectInOSR is the runtime helper that fills in that object’s storage during exit.

The bug is that slots which were never written by the optimized code (‘unwritten slots’) were handled incorrectly while populating the butterfly, so an element that had no corresponding store was left in an inconsistent/uninitialized state rather than being filled with the array hole. When the materialized array is subsequently read or written (the test does ret[0]=1 after arr.map(f)), that slot holds a garbage value instead of a valid empty/hole JSValue — an uninitialized-value / type-confusion-class condition.

The fix corrects operationPopulateObjectInOSR to initialize unwritten slots properly for PhantomNewArrayWithButterfly so every element of the materialized array is a valid JSValue.

The restored invariant is that OSR-exit materialization of a sunk array leaves no element uninitialized. NOTE: the pinned commit (392f508e) contains only the regression test (JSTests/stress/ftl-osr-exit-phantom-array-unwritten-slot.js); the source change to operationPopulateObjectInOSR is described authoritatively by the commit message but is not shown line-by-line in this commit’s diff, so the exact edited lines are taken from the commit’s own description rather than a shown hunk. The test tiers a function that maps over an array with a callback that deopts, forcing the phantom array to materialize on OSR exit.

Key insight
When materializing a sunk PhantomNewArrayWithButterfly on OSR exit, operationPopulateObjectInOSR mishandled elements that were never written, leaving a slot uninitialized instead of the array hole — a garbage JSValue exposed on later access.

Attack Path

  1. Reach the FTL with a sunk array Run JS (e.g. Array.prototype.map with a callback) hot enough that the JIT sinks an array-with-butterfly allocation as PhantomNewArrayWithButterfly.
  2. Leave a slot unwritten Arrange the optimized code so some array element has no corresponding store before an OSR exit.
  3. Force OSR-exit materialization Trigger a deopt (the test uses (0)[0] throwing) so operationPopulateObjectInOSR materializes the phantom array, mishandling the unwritten slot.
  4. Use the uninitialized slot Read/write that element (ret[0]=1) to operate on a garbage JSValue, an uninitialized-value/type-confusion primitive in WebContent (advisory: crash).

Impact Assessment

A JIT correctness bug in the WebContent process: an OSR-exit-materialized array could expose an uninitialized element, which the advisory rates as a process crash. An uninitialized-JSValue read is a potential type-confusion primitive, though the pinned commit shows only the regression test, so the strength of any escalation is not demonstrated in the diff itself.

Changed Functions

FunctionChangeNotes
operationPopulateObjectInOSR (PhantomNewArrayWithButterfly)
Source/JavaScriptCore/dfg/DFGOperations.cpp
modified Per the commit message, corrects handling of unwritten slots when materializing a PhantomNewArrayWithButterfly on OSR exit so uninitialized elements are filled with the hole instead of garbage. (Source change described by the commit; the pinned commit carries the regression test.)
ftl-osr-exit-phantom-array-unwritten-slot.js
JSTests/stress/ftl-osr-exit-phantom-array-unwritten-slot.js
added Regression test that deopts while mapping over an array, forcing OSR-exit materialization of a phantom array with an unwritten slot.

Files Changed

  • JSTests/stress/ftl-osr-exit-phantom-array-unwritten-slot.js

Audit Directions

  • Same helper: other phantom materializations
    Audit operationPopulateObjectInOSR and sibling materialization helpers for how unwritten indices/properties are initialized across PhantomNewArray, PhantomNewArrayWithConstantSize, and object variants.
  • Object-allocation sinking init
    Grep FTL object-allocation-sinking / OSR-exit materialization for butterfly/element fill loops that assume every slot was written.
diff --git a/JSTests/stress/ftl-osr-exit-phantom-array-unwritten-slot.js b/JSTests/stress/ftl-osr-exit-phantom-array-unwritten-slot.js
new file mode 100644
index 000000000000..a285bbf64df8
--- /dev/null
+++ b/JSTests/stress/ftl-osr-exit-phantom-array-unwritten-slot.js
@@ -0,0 +1,13 @@
+function opt() {
+    const arr = [0,0,0,0,0,0,0];
+    function f() {
+        arr[0];
+        (0)[0];
+        return arr;
+    }
+    const ret = arr.map(f)
+    ret[0] = 1
+}
+for (let i = 0; i < 200; i++) {
+    opt()
+}
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker.