[iOS][Fabric] `RCTSwitchComponentView onChange:` dereferences `_eventEmitter` without a null check (EXC_BAD_ACCESS after view recycle)
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- objective-c, react-native
- Domain
- mobile
Research direction
Read React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm, especially onChange: and the nearby recycle handling referenced in the issue. Compare the event emitter guards in the sibling component views named in the report, then check the relevant Switch tests or add coverage for a recycled view if the existing tests expose this path. Done means onChange: safely handles a cleared emitter and existing Switch behavior remains covered.
Written by the indexing model from the issue text.
Description
Environment
- react-native 0.88.0 (first seen on 0.86.0; the file is byte-identical in both), New Architecture
- iOS 26.5.2 device (production crash), same code path on iOS 27
- Expo SDK 58 (not involved)
Description
-[RCTSwitchComponentView onChange:] (React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm:105-114) ends with
static_cast<const SwitchEventEmitter &>(*_eventEmitter) // line 113
.onChange(SwitchEventEmitter::OnChange{.value = static_cast<bool>(sender.on)});
with no check that _eventEmitter is set. RCTViewComponentView -prepareForRecycle resets it (RCTViewComponentView.mm:779, _eventEmitter.reset();), while _props stays valid, so the earlier *_props dereference does not fail.
Production crash (0.86.0, line 114 of that version), iOS 26.5.2:
EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS at 0x0000000000000030
0 React std::weak_ptr<EventDispatcher const>::lock()
1 React EventEmitter::dispatchEvent(...)
4 React SwitchEventEmitter::onChange(...)
5 React -[RCTSwitchComponentView onChange:]
6 UIKitCore -[UIApplication sendAction:to:from:forEvent:]
9 UIKitCore -[UISwitchModernVisualElement sendStateChangeActions]
11 UIKitCore -[UISwitchModernVisualElement _handleLongPressWithGestureLocationInBounds:...]
12 UIKitCore -[_UIAfterCACommitBlock run]
0x30 is a null this plus the eventDispatcher_ offset in EventEmitter.
Reproduction
Intermittent, not reproduced on demand. Conditions: iOS 26+, where the redesigned UISwitch (UISwitchModernVisualElement) delivers the state-change action from a deferred _UIAfterCACommitBlock instead of synchronously on touch-up (seen when the switch is dragged or long-pressed rather than tapped). If React re-renders and recycles the Switch view between the gesture ending and that block running, prepareForRecycle has already cleared _eventEmitter and onChange: runs on the recycled view.
Root cause
Missing null guard. Sibling components in the same directory tree already have it: RCTScrollViewComponentView, RCTImageComponentView, RCTModalHostViewComponentView, RCTVirtualViewComponentView (if (!_eventEmitter) { return; }), and RCTTextInputComponentView tests _eventEmitter before use at several sites. Switch is the outlier.
Proposed fix
--- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm
+++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm
@@ -110,6 +110,9 @@ - (void)onChange:(UISwitch *)sender
return;
}
+ if (!_eventEmitter) {
+ return;
+ }
static_cast<const SwitchEventEmitter &>(*_eventEmitter)
.onChange(SwitchEventEmitter::OnChange{.value = static_cast<bool>(sender.on)});
}
We carry this as a local patch. Dropping the event is the right behaviour: the view has been recycled and no longer represents that React node.
Disclosure: drafted with AI assistance (Claude) from a patch we carry locally; code references were checked against the published package sources. Happy to clarify or open a PR.
- Dominant language
- C++
- Stars
- 127k
- Forks
- 25.3k
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from react/react-native
-
Linking.getInitialURL() returns the task's first link after a link relaunches a reclaimed Android appPossibly taken @YevheniiKotyrlo claimed this 7 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
react/react-native#59006 · 2 comments ·
Maintainers usually reply within 2 days
-
Fabric TextInput: prepareForRecycle leaves stale inputAccessoryViewButtonLabel (empty Done bar)Possibly taken @jkasprzyk17 claimed this 6 days ago. OpenNeeds: Author Feedback Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
react/react-native#58952 · 1 comment ·
Maintainers usually reply within 2 days
-
[iOS][Fabric] TextInput drops a keystroke right after the first character typed into an empty field (_textOf:equals: compares attributes of a focused field)Possibly taken A pull request linked to this issue is open or already merged. OpenNeeds: Attention Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
react/react-native#58904 · 3 comments ·
Maintainers usually reply within 2 days
-
Needs: Author Feedback Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
react/react-native#58659 · 2 comments ·
Maintainers usually reply within 2 days
-
Needs: Author Feedback Needs: Repro
Difficulty 1/5 Under an hour Newbie friendliness 92/100
react/react-native#58621 · 1 comment ·
Maintainers usually reply within 2 days
All issues in react/react-native
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
category:port-update
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 2 days
-
(S1 - Need confirmation)
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
CleverRaven/Cataclysm-DDA#89194 ·
Maintainers usually reply within 1 day
-
reproduced
Difficulty 1/5 Under an hour Newbie friendliness 67/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day