CVE-2026-65333
Overview
Background
- Post-dominator / BackwardsGraph
- B is a post-dominator of A if every path from A to program exit passes through B; B3 computes it by reversing the CFG with a synthetic root over all terminals and back-edge sources.
- Latch / back-edge source
- A block that jumps back to a loop header; an exit-less latch lets control loop forever without reaching other latches.
- LICM
- Loop-invariant code motion hoists computations out of loops; hoisting a control-dependent memory access is only safe if it truly post-dominates the loop entry.
Root Cause Analysis
This fixes a B3 post-dominator miscomputation that could let loop-invariant code motion (LICM) hoist a control-dependent memory access out of a loop. B3 computes post-dominators via BackwardsGraph, which reverses the CFG and gives a synthetic reverse root a successor for every terminal block AND every back-edge source (latch). The correctness of LICM (and other control-equivalence consumers) depends on the resulting post-dominator relation. Consider a loop whose header has two latches: ‘success’ (which can also exit the loop) and ‘failure’ (an exit-less latch that just jumps back to the header). Control can stay in the loop forever by repeatedly taking the exit-less ‘failure’ latch without ever reaching ‘success’. Therefore ‘success’ must NOT post-dominate the header or the loop entry.
Pre-patch, if an exit-less back-edge source like ‘failure’ was omitted from the synthetic reverse root’s successors, then in the reversed CFG the header was reachable only through ‘success’, so ‘success’ FALSELY post-dominated the header (and the loop entry). B3 LICM would then treat a read guarded by the ‘success’ path as always-executed and hoist that control-dependent read out of the loop, so it runs unconditionally (even when control never legitimately reaches it) — an invalid/out-of-bounds read (bad hoisting).
The fix ensures every back-edge source, including exit-less latches, is a successor of the synthetic reverse root in BackwardsGraph so post-dominance is computed correctly and LICM does not hoist the control-dependent access. The added B3 unit test (testBackwardsDominatorsWithMultipleBackEdges) builds exactly this two-latch loop and asserts ‘success’ does not post-dominate the header/root. (The source change is in B3’s BackwardsGraph/BackwardsDominators; this diff shows the authoritative test that documents the property, per its comment.)
Attack Path
- Reach the B3/FTL JIT Run JS that the FTL compiles through B3 with a loop shaped to have two latches, one of them exit-less.
- Induce false post-dominance The exit-less latch is omitted from the reverse-root successors, so an exiting latch falsely post-dominates the header.
- Hoist a control-dependent read LICM treats a guarded (control-dependent) memory access as always-executed and hoists it out of the loop.
- Out-of-bounds read The hoisted access runs unconditionally, performing an invalid/out-of-bounds read and crashing the WebContent process.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
B3 BackwardsGraph / BackwardsDominators (reverse-root successors)Source/JavaScriptCore/b3/B3BackwardsGraph.h |
modified | Includes every back-edge source (including exit-less latches) as a successor of the synthetic reverse root so post-dominance is correct and LICM cannot falsely treat an exiting latch as post-dominating the header. (Fix location per the added test's documentation.) |
testBackwardsDominatorsWithMultipleBackEdgesSource/JavaScriptCore/b3/testb3_7.cpp |
added | Unit test building a two-latch loop (one latch exit-less) and asserting the exiting latch does not post-dominate the header/root. |
Files Changed
JSTests/wasm/gc/backwards-graph-multi-backedge-licm.jsSource/JavaScriptCore/b3/B3Procedure.hSource/JavaScriptCore/b3/testb3.hSource/JavaScriptCore/b3/testb3_1.cppSource/JavaScriptCore/b3/testb3_7.cppSource/WTF/wtf/BackwardsGraph.h
Audit Directions
- Reverse-root successor setAudit B3BackwardsGraph for which blocks seed the synthetic reverse root; every terminal and every back-edge source (including exit-less latches) must be included.
- Control-equivalence consumersReview LICM and other post-dominator/control-equivalence users for reliance on the post-dominator relation across irreducible/multi-latch loops.