Skip to content

Commit 06e37a3

Browse files
committed
Skip non-owned subtrees in roundLayoutResultsToPixelGrid
roundLayoutResultsToPixelGrid recurses into every yoga child and writes rounded positions and dimensions back into each node. Unlike the layout pass, which clones children before mutating them (cloneChildrenIfNeeded), the rounding pass crosses the ownership frontier into subtrees that are structurally shared with other shadow trees. Under Fabric, two trees can run layout concurrently: commits run layoutIfNeeded on candidate trees before taking the commit mutex, and concurrent committers (React on the JS thread and a library committing from another thread) share every unchanged subtree. Both rounding passes then mutate the same shared yoga nodes. ThreadSanitizer reports this as a data race: reads at PixelGrid.cpp:72/75 against writes at PixelGrid.cpp:89/109 via Node::setLayoutPosition. Skipping children whose owner is not the current node is safe: - YogaLayoutableShadowNode::layout only copies metrics from children with hasNewLayout, and asserts those children are owned (YGNodeGetOwner(childYogaNode) == &yogaNode_). - hasNewLayout is only set on nodes the pass performed layout on, so nodes past the ownership frontier are cache-restored, keep the flag unset, and the metrics-copying recursion never descends into them. - The shadow nodes past the frontier were not cloned in this commit, so they are sealed and cannot accept new LayoutMetrics at all. Rounded values written to non-owned nodes therefore have no reader; the writes can only corrupt the state of other trees. The guard mirrors the existing owner checks in Node::cloneChildrenIfNeeded and YGNodeFreeRecursive ("Don't free shared nodes that we don't own"). Observed in react-native-reanimated's ThreadSanitizer nightly CI: https://github.com/software-mansion/react-native-reanimated/actions/runs/32811464205/job/97691453444
1 parent e519d03 commit 06e37a3

1 file changed

Lines changed: 3 additions & 0 deletions

File tree

  • packages/react-native/ReactCommon/yoga/yoga/algorithm

packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ void roundLayoutResultsToPixelGrid(
128128
}
129129

130130
for (yoga::Node* child : node->getChildren()) {
131+
if (child->getOwner() != node) {
132+
continue;
133+
}
131134
roundLayoutResultsToPixelGrid(child, absoluteNodeLeft, absoluteNodeTop);
132135
}
133136
}

0 commit comments

Comments
 (0)