Commit 06e37a3
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/976914534441 parent e519d03 commit 06e37a3
1 file changed
Lines changed: 3 additions & 0 deletions
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
131 | 134 | | |
132 | 135 | | |
133 | 136 | | |
| |||
0 commit comments