[Fabric][iOS] Differ creates a mounted view again when a child with negative zIndex moves in a nested flatten/unflatten
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 40/100
Línea de trabajo
The bug is in Fabric's differ in Differentiator.cpp, specifically in calculateShadowViewMutationsFlattener. Start by examining the reproducer at https://github.com/pawicao/rn-differ-zindex-flatten-repro to understand the tree shape with nested views and negative zIndex. Look at the sorting by orderIndex and the handling of ShadowViewNodePair in subVisitedNewMap/subVisitedOldMap. The fix likely involves ensuring K is not incorrectly marked for deletion/creation. Run the iOS app from the reproducer to see the crash, then trace through the differ logic with the provided mutation logs.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
The Fabric differ (Differentiator.cpp) makes incorrect mutations for one tree shape. It creates a view that is already mounted. Or it deletes a view that only moves.
The tree has three nested views: Q > U > F. Q and F have opacity. F has three children. The second child (K) has zIndex: -1.
When the opacity moves from F to U in one commit, U unflattens and F flattens. The children of F move to U. The opposite change also causes the bug.
Result:
- iOS Debug: the app crashes on the first change.
RCTComponentViewRegistryasserts: "Attempt to dequeue already registered component." - iOS Release: the app crashes with SIGSEGV in
-[RCTMountingManager performTransaction:](I saw this on 0.88.0-rc.2). - Android: the app does not crash. The Android mounting layer ignores a
Createfor a tag that it already has. The differ output is still incorrect.
If you remove zIndex: -1 from K, the differ output is correct.
Cause (suspected):
This below cause came from AI assisted analysis of the situation
In calculateShadowViewMutationsFlattener, the differ sorts the children by orderIndex. Thus it visits K before F. At that time, nothing has matched K, so K becomes a delete or create candidate. Then the nested (un)flattening of F matches K through a different ShadowViewNodePair. It records K in subVisitedNewMap or subVisitedOldMap. But the last loop over the candidates checks only treeChildPair.inOtherTree(). Thus the differ deletes or creates K.
A related bug is in the same function. In the "flatten parent, unflatten child" branch, auto unvisitedItPair = *unvisitedOtherNodesIt->second; keeps the address of a local copy in unvisitedRecursiveChildPairs. This pointer is not valid after the loop iteration.
We found this bug through crash reports in react-native-reanimated (Layout Animations). The reproducer does not use Reanimated or any other library.
Steps to reproduce
- Clone https://github.com/pawicao/rn-differ-zindex-flatten-repro.
- Go to the
ReproducerAppdirectory. - Run
yarn install. - Run
cd ios && bundle install && bundle exec pod install && cd ... - Run
yarn ios. - Wait approximately 0.5 seconds. The app changes the tree automatically.
- Notice the crash.
React Native Version
0.87.1
Affected Platforms
Runtime - iOS
Output of npx @react-native-community/cli info
System:
OS: macOS 27.0
CPU: (10) arm64 Apple M4
Memory: 271.25 MB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.23.2
path: /Users/oskarpawica/.nvm/versions/node/v22.23.2/bin/node
Yarn:
version: 1.22.22
path: /Users/oskarpawica/.nvm/versions/node/v22.23.2/bin/yarn
npm:
version: 10.9.8
path: /Users/oskarpawica/.nvm/versions/node/v22.23.2/bin/npm
Watchman: Not Found
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 27.0
- iOS 27.0
- macOS 27.0
- tvOS 27.0
- visionOS 27.0
- watchOS 27.0
Android SDK: Not Found
IDEs:
Android Studio: 2025.1 AI-251.26094.121.2513.14007798
Xcode:
version: 27.0/27A266a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.17
path: /opt/homebrew/opt/openjdk@17/bin/javac
Ruby:
version: 3.4.5
path: /opt/homebrew/opt/ruby/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 20.2.0
wanted: 20.2.0
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.87.1
wanted: 0.87.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'RCTComponentViewRegistry: Attempt to dequeue already registered component.'
9 libobjc.A.dylib objc_exception_throw
10 Foundation -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:]
11 React -[RCTComponentViewRegistry dequeueComponentViewWithComponentHandle:tag:]
12 React RCTPerformMountInstructions(std::vector<facebook::react::ShadowViewMutation> const&, RCTComponentViewRegistry*, RCTMountingTransactionObserverCoordinator&, int)
13 React -[RCTMountingManager performTransaction:]::$_2::operator()(facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&) const
20 React facebook::react::TelemetryController::pullTransaction(...)
21 React -[RCTMountingManager performTransaction:]
22 React -[RCTMountingManager initiateTransaction:]
23 React __42-[RCTMountingManager scheduleTransaction:]_block_invoke
24 React __RCTExecuteOnMainQueue_block_invoke
Mutations from the differ (tags from a trace of the same tree):
U unflattens, F flattens:
Remove 146 <- 148 @2 | Remove 142 <- 148 @1 | Remove 144 <- 148 @0 | Create 150 | Create 144 | Insert 150 -> 152 @1 | Insert 144 -> 150 @0 | ... | Delete 148
^^^^^^^^^^ K is mounted
U flattens, F unflattens:
Remove 182 <- 186 @2 | Remove 178 <- 186 @1 | Remove 180 <- 186 @0 | Remove 186 <- 188 @0 | Delete 186 | Delete 180 | Create 184 | Insert 180 -> 184 @0 | ...
^^^^^^^^^^ K moves, but the differ deletes it
MANDATORY Reproducer
https://github.com/pawicao/rn-differ-zindex-flatten-repro
Screenshots and Videos
https://github.com/user-attachments/assets/9a4275ac-991c-4d74-a07c-37a7d899bc71
- Lenguaje dominante
- C++
- Estrellas
- 127k
- Forks
- 25.3k
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de react/react-native
-
Needs: Author Feedback Needs: Repro
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
react/react-native#58621 · 1 comentario ·
-
Needs: Author Feedback Needs: Repro
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
react/react-native#58610 · 1 comentario ·
-
Needs: Triage :mag:
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
react/react-native#58565 · 1 comentario · 2 reacciones ·
-
Needs: Author Feedback Needs: Repro
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
react/react-native#58555 · 5 comentarios · 2 reacciones ·
-
Needs: Attention Needs: Repro
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
react/react-native#58526 · 2 comentarios ·
Todos los issues de react/react-native
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
flutter-webrtc/flutter-webrtc#2206 ·
-
litertlm-android AAR ships no consumer ProGuard rules → "mid == null" SIGABRT in minified apps Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
google-ai-edge/LiteRT-LM#3739 ·
-
Component: GLib
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
-
Mute ydb/tests/functional/dstool/test_canonical_requests.py.Test.test_group_take_snapshot in main Abiertoai_reviewed
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
ydb-platform/ydb#53974 · 3 comentarios ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
google/libultrahdr#485 ·