From 6c77c51abf62a5aca58c19c0468ffe7b0e428400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= Date: Thu, 27 Aug 2026 11:49:04 -0700 Subject: [PATCH] Skip non-owned subtrees in roundLayoutResultsToPixelGrid Summary: > [!NOTE] > **This PR description is AI-generated.** Fabric runs layout on candidate trees before taking the commit mutex, and concurrent commits share every unchanged subtree, so Yoga's pixel-grid rounding pass could write rounded positions and dimensions into the same shared `yoga::Node` from two threads at once. The layout pass itself never mutates nodes it does not own (`Node::cloneChildrenIfNeeded`), but `roundLayoutResultsToPixelGrid` recursed across the ownership frontier. I made the rounding recursion skip children whose owner is not the current node, mirroring the existing owner checks in `Node::cloneChildrenIfNeeded` and `YGNodeFreeRecursive`. The skipped writes had no reader: `YogaLayoutableShadowNode::layout` copies metrics only from children with `hasNewLayout` (asserting they are owned), `hasNewLayout` is set only on nodes the pass laid out, and the shadow nodes past the frontier are sealed, so their `LayoutMetrics` could not change in that commit anyway. ## Changelog: [GENERAL] [FIXED] - Fix data race between concurrent Fabric commits in Yoga's pixel-grid rounding pass X-link: https://github.com/react/react-native/pull/58144 Reviewed By: christophpurrer Differential Revision: D117688567 Pulled By: zeyap --- yoga/algorithm/PixelGrid.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yoga/algorithm/PixelGrid.cpp b/yoga/algorithm/PixelGrid.cpp index 61de2be2e8..5c5a3b7ffb 100644 --- a/yoga/algorithm/PixelGrid.cpp +++ b/yoga/algorithm/PixelGrid.cpp @@ -128,6 +128,9 @@ void roundLayoutResultsToPixelGrid( } for (yoga::Node* child : node->getChildren()) { + if (child->getOwner() != node) { + continue; + } roundLayoutResultsToPixelGrid(child, absoluteNodeLeft, absoluteNodeTop); } }