Skip to content

Fix TextInput state retain chain in AndroidTextInputShadowNode - #59980

Open
kellarwindland wants to merge 1 commit into
react:mainfrom
kellarwindland:export-D131297146
Open

kellarwindland wants to merge 1 commit into
react:mainfrom
kellarwindland:export-D131297146

Conversation

@kellarwindland

Copy link
Copy Markdown

Summary:
AndroidTextInputShadowNode::getAttributedString builds the fragment for a controlled value with parentShadowView = ShadowView(*this). A full ShadowView carries the node's current state and props. updateStateIfNeeded stores that attributed string in the next AndroidTextInputState (reactTreeAttributedString), so every new state keeps the previous state (and props) alive. The chain grows by one link per value change for as long as the input stays mounted.

Two effects:

  • Memory: native heap grows with every change to a controlled TextInput and is only released on unmount.
  • Crash: on unmount the whole chain is destroyed recursively on the JS thread. Long chains overflow the stack, and crash stacks repeat State → AttributedString → Fragment → ShadowView → State dozens of times before ending in a SIGSEGV in ~AndroidTextInputState().

D94267721 fixed the same retain chain for iOS/macOS by adding shadowViewFromShadowNode() in BaseTextInputShadowNode.h. AndroidTextInputShadowNode does not inherit from BaseTextInputShadowNode, so Android still had the bug.

This change clears props and state on the parent ShadowView before storing it in the fragment, mirroring the iOS fix. On Android, parentShadowView is only read for tag, componentHandle and layoutMetrics. Its state and props are never read.

Changelog:

[Android] [Fixed] - Fix memory leak in TextInput: each state retained the previous one, which could overflow the stack on unmount

Differential Revision: D131297146

Summary:
`AndroidTextInputShadowNode::getAttributedString` builds the fragment for a controlled `value` with `parentShadowView = ShadowView(*this)`. A full `ShadowView` carries the node's current `state` and `props`. `updateStateIfNeeded` stores that attributed string in the next `AndroidTextInputState` (`reactTreeAttributedString`), so every new state keeps the previous state (and props) alive. The chain grows by one link per value change for as long as the input stays mounted.

Two effects:
- Memory: native heap grows with every change to a controlled `TextInput` and is only released on unmount.
- Crash: on unmount the whole chain is destroyed recursively on the JS thread. Long chains overflow the stack, and crash stacks repeat `State → AttributedString → Fragment → ShadowView → State` dozens of times before ending in a SIGSEGV in `~AndroidTextInputState()`.

D94267721 fixed the same retain chain for iOS/macOS by adding `shadowViewFromShadowNode()` in `BaseTextInputShadowNode.h`. `AndroidTextInputShadowNode` does not inherit from `BaseTextInputShadowNode`, so Android still had the bug.

This change clears `props` and `state` on the parent `ShadowView` before storing it in the fragment, mirroring the iOS fix. On Android, `parentShadowView` is only read for `tag`, `componentHandle` and `layoutMetrics`. Its `state` and `props` are never read.

## Changelog:

[Android] [Fixed] - Fix memory leak in TextInput: each state retained the previous one, which could overflow the stack on unmount

Differential Revision: D131297146
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 12, 2026
@meta-codesync

meta-codesync Bot commented Nov 12, 2026

Copy link
Copy Markdown

@kellarwindland has exported this pull request. If you are a Meta employee, you can view the originating Diff in D131297146.

@javache javache left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants