← All issues

[3] [JSC FTL] Fix indexing-type mismatch in OSR exit array materialization during bad time

Severity: High | Component: JSC FTL JIT | eba64ef

Rated High because the diff fixes a type confusion between a SlowPutArrayStorage Structure and a contiguous butterfly on a script-visible JSArray produced by FTL OSR exit; the resulting cell is read/written through ArrayStorage codepaths over contiguous memory, yielding controlled out-of-bounds against adjacent heap.

operationMaterializeObjectInOSR is changed to choose the rematerialized array's structure via originalArrayStructureForIndexingType (preserves contiguous structure regardless of bad-time state), populate the butterfly, then call switchToSlowPutArrayStorage(vm) only after the butterfly is consistent. operationPopulateObjectInOSR gains a hasAnyArrayStorage branch for hole fixup after the migration.

Source/JavaScriptCore/ftl/FTLOperations.cpp

- Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(materialization->indexingType());
+ Structure* structure = globalObject->originalArrayStructureForIndexingType(materialization->indexingType());
JSArray* array = JSArray::createWithButterfly(vm, nullptr, structure, butterfly);
...
+ if (globalObject->isHavingABadTime())
+ array->switchToSlowPutArrayStorage(vm);

Type confusion between a SlowPutArrayStorage Structure and a contiguous-shaped butterfly during FTL OSR materialization of a sunk array.

PhantomNewArrayWithButterfly rematerialization no longer queries arrayStructureForIndexingTypeDuringAllocation; it uses originalArrayStructureForIndexingType. After the butterfly is filled (contiguous slots, public/vector length set as for contiguous), the array is migrated to SlowPutArrayStorage via the dedicated transition. operationPopulateObjectInOSR learns to fix holes on either the contiguous or ArrayStorage shape.

FTL OSR exit reconstructs objects whose materialization the optimizer sunk. For PhantomNewArrayWithButterfly the runtime allocates a fresh JSArray, picks a Structure, allocates a butterfly, and fills it. JSC's "bad time" mode — entered when indexed accessors are installed on Array.prototype / Object.prototype — switches the global object's default array structures to SlowPutArrayStorage, which has a different butterfly header (m_vector, m_numValuesInVector, m_sparseMap) and slot layout from contiguous.

Pre-fix, the structure was queried via arrayStructureForIndexingTypeDuringAllocation — which returns the current default for the indexing type, i.e. the bad-time substitute when applicable. The butterfly fill code was hard-wired for contiguous: it wrote into butterfly->contiguous().atUnsafe(index) and set the contiguous public/vector length. The resulting JSArray advertised SlowPutArrayStorage via its Structure while its butterfly was a contiguous shape with no ArrayStorage header.

🔒

The compile-time and exit-time views of an array's layout drift apart under a specific script-reachable global state transition — the analysis works through what that lets an attacker build, end to end.

Subscribe to read more

🔒

Four reusable audit patterns identified across FTL/DFG deoptimization runtimes, with specific helpers and call sites flagged for variant discovery.

Subscribe to read more