Remove tag from allocatedViewRegistry in destroyUnmountedShadowNode (#56274)#56274
Open
javache wants to merge 1 commit intofacebook:mainfrom
Open
Remove tag from allocatedViewRegistry in destroyUnmountedShadowNode (#56274)#56274javache wants to merge 1 commit intofacebook:mainfrom
javache wants to merge 1 commit intofacebook:mainfrom
Conversation
javache
added a commit
to javache/react-native
that referenced
this pull request
Mar 30, 2026
…acebook#56274) Summary: When a ShadowNode is destroyed (e.g. from a superseded concurrent render or React Transition), destroyUnmountedShadowNode calls Java destroyUnmountedView which deletes the view from tagToViewState. However, the C++ allocatedViewRegistry was not updated, leaving a stale entry. This causes a crash when a subsequent executeMount encounters a Create mutation for the same tag: allocatedViewTags.contains(tag) returns true (stale entry from preallocate), so the Create mount item is skipped. But the Java view was already destroyed. When subsequent mount items (Insert, UpdateState, etc.) try to reference the tag, getViewState() throws RetryableMountingLayerException because the tag is not in tagToViewState. The fix mirrors what the normal Delete mutation path already does (line 638: allocatedViewTags.erase(tag)) - ensuring allocatedViewRegistry stays in sync with the Java-side tagToViewState. Changelog: [Android][Fixed] - Fix crash from stale preallocated view registry after concurrent render cancellation Differential Revision: D98729251
b6cfa04 to
f4d0c57
Compare
javache
added a commit
to javache/react-native
that referenced
this pull request
Mar 30, 2026
…acebook#56274) Summary: When a ShadowNode is destroyed (e.g. from a superseded concurrent render or React Transition), destroyUnmountedShadowNode calls Java destroyUnmountedView which deletes the view from tagToViewState. However, the C++ allocatedViewRegistry was not updated, leaving a stale entry. This causes a crash when a subsequent executeMount encounters a Create mutation for the same tag: allocatedViewTags.contains(tag) returns true (stale entry from preallocate), so the Create mount item is skipped. But the Java view was already destroyed. When subsequent mount items (Insert, UpdateState, etc.) try to reference the tag, getViewState() throws RetryableMountingLayerException because the tag is not in tagToViewState. The fix mirrors what the normal Delete mutation path already does (line 638: allocatedViewTags.erase(tag)) - ensuring allocatedViewRegistry stays in sync with the Java-side tagToViewState. Changelog: [Android][Fixed] - Fix crash from stale preallocated view registry after concurrent render cancellation Differential Revision: D98729251
f4d0c57 to
6fd0273
Compare
…acebook#56274) Summary: Pull Request resolved: facebook#56274 When a ShadowNode is destroyed (e.g. from a superseded concurrent render or React Transition), destroyUnmountedShadowNode calls Java destroyUnmountedView which deletes the view from tagToViewState. However, the C++ allocatedViewRegistry was not updated, leaving a stale entry. This causes a crash when a subsequent executeMount encounters a Create mutation for the same tag: allocatedViewTags.contains(tag) returns true (stale entry from preallocate), so the Create mount item is skipped. But the Java view was already destroyed. When subsequent mount items (Insert, UpdateState, etc.) try to reference the tag, getViewState() throws RetryableMountingLayerException because the tag is not in tagToViewState. The fix mirrors what the normal Delete mutation path already does (line 638: allocatedViewTags.erase(tag)) - ensuring allocatedViewRegistry stays in sync with the Java-side tagToViewState. Changelog: [Android][Fixed] - Fix crash from stale preallocated view registry after concurrent render cancellation Differential Revision: D98729251
6fd0273 to
172e07b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
When a ShadowNode is destroyed (e.g. from a superseded concurrent render
or React Transition), destroyUnmountedShadowNode calls Java
destroyUnmountedView which deletes the view from tagToViewState. However,
the C++ allocatedViewRegistry was not updated, leaving a stale entry.
This causes a crash when a subsequent executeMount encounters a Create
mutation for the same tag: allocatedViewTags.contains(tag) returns true
(stale entry from preallocate), so the Create mount item is skipped.
But the Java view was already destroyed. When subsequent mount items
(Insert, UpdateState, etc.) try to reference the tag, getViewState()
throws RetryableMountingLayerException because the tag is not in
tagToViewState.
The fix mirrors what the normal Delete mutation path already does
(line 638: allocatedViewTags.erase(tag)) - ensuring allocatedViewRegistry
stays in sync with the Java-side tagToViewState.
Changelog: [Android][Fixed] - Fix crash from stale preallocated view registry after concurrent render cancellation
Differential Revision: D98729251