Skip to content

[0.83] fix(pointer): crash (0xc0000005) when the pointer-capturing component has been unmounted - #16334

Open
FaithfulAudio wants to merge 2 commits into
microsoft:0.83-stablefrom
FacilitronWorks:fix/pointer-capture-null-guard
Open

[0.83] fix(pointer): crash (0xc0000005) when the pointer-capturing component has been unmounted#16334
FaithfulAudio wants to merge 2 commits into
microsoft:0.83-stablefrom
FacilitronWorks:fix/pointer-capture-null-guard

Conversation

@FaithfulAudio

@FaithfulAudio FaithfulAudio commented Jul 26, 2026

Copy link
Copy Markdown

fix(pointer): crash (0xc0000005) when the pointer-capturing component has been unmounted

Problem

A Fabric/Composition app crashes with an access violation (0xc0000005) during ordinary
list interaction on a touch device. Reproduced on a production RNW 0.83.2 new-arch app
(Facilitron FIT) by panning a virtualized inspection list: scroll the list, let
virtualization recycle the row that currently holds pointer capture, then press or release
again. The process dies rather than throwing.

Root cause

Both capture paths in CompositionEventHandler look the capturing component up by its
cached tag and then dereference the result without checking it:

auto targetComponentView =
    fabricuiManager->GetViewRegistry().componentViewDescriptorWithTag(m_pointerCapturingComponentTag).view;

winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(targetComponentView)
    ->OnPointerCaptureLost();

m_pointerCapturingComponentTag can outlive the component it names. If the capturing
component is unmounted without releasing capture — exactly what list/ScrollView
virtualization does when it recycles a row mid-pan — componentViewDescriptorWithTag
returns a descriptor whose .view is null. winrt::get_self on a null projected
reference yields a null pointer, and the ->OnPointerCaptureLost() call dereferences it.

The same unguarded pattern appears twice:

  • CompositionEventHandler::CapturePointer — when a new capture displaces a previous one
  • CompositionEventHandler::releasePointerCapture — when capture is released

This is independent of any pointer-routing behavior; it is purely a missing lifetime check
on a cached tag.

Fix

Null-check targetComponentView before notifying, at both sites. When the view is gone
there is nothing to notify — in CapturePointer the stale tag is overwritten immediately
below, and in releasePointerCapture the tag is cleared by the existing
m_capturedPointers.size() == 0 branch. So skipping the notify loses no state transition.

Confined to vnext/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp.
No header, signature, or public-API change.

Validation

Built from source (UseExperimentalNuget=false) into the production RNW 0.83.2
new-arch app, so the patched Microsoft.ReactNative.dll is what was exercised rather than
a prebuilt NuGet package.

  • Before: panning the FIT inspection list and interacting with a recycled row terminated
    the process with 0xc0000005. Reproducible.
  • After: an automated soak drove the guarded paths with real PT_TOUCH contacts
    (InitializeTouchInjection / InjectTouchInput — synthetic mouse input does not exercise
    RNW's touch path). Across 8 cycles on the live Inspection List: 10 press-a-row-then-pan-
    far-while-still-held events (the row is recycled underneath the held contact, which is the
    exact sequence that produced the null view), 3 expand/collapse mount-unmount churns
    under the pointer, and 8 hard flicks during mount settle. No crash; the process stayed
    responsive throughout. A separate 20-tap soak including capture-loss and scroll-steal
    cases also passed with no dropped taps.

Honest limit on that evidence: the binary under test already contains this guard, so the
absence of a crash is consistent with the fix but does not prove causation — demonstrating
that would need an otherwise-identical build without the guard, which I have not produced
(it is a ~4.5 hour from-source framework build). What the soak does establish is that the
guarded code paths are reached repeatedly and behave correctly. The root cause itself is
plain from the code: m_pointerCapturingComponentTag can outlive the component it names,
and componentViewDescriptorWithTag(...).view is documented to return a null .view for a
stale tag.

Caveats for reviewers:

  • Silently skipping the notify is the conservative choice, but it does mean a component
    unmounted while holding capture never observes OnPointerCaptureLost. If you would
    rather RNW proactively released capture at unmount time (in the component teardown path)
    so the tag can never go stale, that is a larger but arguably more correct fix and I am
    happy to take that direction instead.
  • I did not add a test: exercising this needs a component unmounted while holding capture,
    which I could not express in the existing unit-test harness. Pointers to the right
    fixture welcome.
  • Targeting 0.83-stable to match the app in production. Glad to forward-port to main.
Microsoft Reviewers: Open in CodeFlow

…g OnPointerCaptureLost

CapturePointer and releasePointerCapture look the capturing component up by its
cached m_pointerCapturingComponentTag and dereference the result unguarded. That
tag can outlive the component it names: when list/ScrollView virtualization
recycles the capturing row mid-pan, componentViewDescriptorWithTag returns a
descriptor whose .view is null, so winrt::get_self(...)->OnPointerCaptureLost()
dereferences null and terminates the process with 0xc0000005.

Null-check targetComponentView at both sites. Skipping the notify loses no state
transition: CapturePointer overwrites the stale tag immediately below, and
releasePointerCapture clears it via the existing m_capturedPointers.size() == 0
branch.
@FaithfulAudio
FaithfulAudio requested a review from a team as a code owner July 26, 2026 06:45
@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI 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.

Pull request overview

Fixes a native crash in Fabric/Composition pointer-capture handling when the previously capturing component has been unmounted (e.g., via list/ScrollView virtualization), by guarding OnPointerCaptureLost() notifications against a null ComponentView lookup.

Changes:

  • Add null checks before calling winrt::get_self(...)->OnPointerCaptureLost() when resolving the previously capturing component by cached tag.
  • Add explanatory comments describing the stale-tag / null-view scenario leading to 0xc0000005.
  • Add a change file to record the patch-level release note for react-native-windows.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
vnext/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp Adds null guards around stale pointer-capture notifications to prevent dereferencing a null component view.
change/react-native-windows-capture-null-guard.json Records the patch change note for the crash fix.

@acoates-ms

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 1 pipeline(s).

@acoates-ms acoates-ms changed the title fix(pointer): crash (0xc0000005) when the pointer-capturing component has been unmounted [0.83] fix(pointer): crash (0xc0000005) when the pointer-capturing component has been unmounted Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Performance Test Results

Branch: fix/pointer-capture-null-guard
Commit: 3342dd68
Time: 2026-08-03T23:01:12.631Z
Tests: 161/161 passed

✅ Passed

161 scenario(s) across 28 suite(s) — no regressions

SectionList

Scenario Mean Median StdDev Renders vs Baseline
SectionList mount 5.00ms 5.00ms ±0.67ms 1 +0.0%
SectionList unmount 0.20ms 0.00ms ±0.42ms 0 +0.0%
SectionList rerender 11.90ms 12.00ms ±0.57ms 2 +14.3%
SectionList with-3-sections-15-items 6.50ms 5.50ms ±2.32ms 1 +0.0%
SectionList with-5-sections-50-items 6.40ms 6.00ms ±1.35ms 1 +0.0%
SectionList with-10-sections-200-items 6.60ms 6.00ms ±1.26ms 1 +9.1%
SectionList with-20-sections-200-items 5.70ms 5.50ms ±1.77ms 1 +10.0%
SectionList with-section-separator 1.80ms 2.00ms ±0.63ms 1 +0.0%
SectionList with-item-separator 2.50ms 2.00ms ±0.85ms 1 +0.0%
SectionList with-header-footer 3.80ms 3.50ms ±1.87ms 1 +75.0%
SectionList with-section-footer 1.90ms 2.00ms ±0.57ms 1 +0.0%
SectionList with-sticky-section-headers 2.30ms 2.00ms ±1.34ms 1 +0.0%
SectionList with-empty-list 0.50ms 0.50ms ±0.53ms 1 -50.0%
SectionList with-50-sections-1000-items 1.90ms 2.00ms ±0.32ms 1 +0.0%

FlatList

Scenario Mean Median StdDev Renders vs Baseline
FlatList mount 4.40ms 4.00ms ±0.84ms 1 +0.0%
FlatList unmount 0.20ms 0.00ms ±0.42ms 0 +0.0%
FlatList rerender 10.40ms 10.00ms ±1.90ms 2 +11.1%
FlatList with-10-items 4.90ms 5.00ms ±0.32ms 1 +25.0%
FlatList with-100-items 5.70ms 5.00ms ±1.57ms 1 +0.0%
FlatList with-500-items 4.60ms 5.00ms ±0.52ms 1 +25.0%
FlatList with-1000-items 6.70ms 6.50ms ±1.49ms 1 +62.5%
FlatList horizontal 4.60ms 5.00ms ±1.26ms 1 +0.0%
FlatList with-separator 2.00ms 2.00ms ±0.00ms 1 +0.0%
FlatList with-header-footer 1.50ms 1.50ms ±0.53ms 1 -25.0%
FlatList with-empty-list 0.60ms 1.00ms ±0.52ms 1 +100.0%
FlatList with-get-item-layout 2.20ms 2.00ms ±1.75ms 1 +100.0%
FlatList inverted 1.30ms 1.00ms ±0.48ms 1 -33.3%
FlatList with-num-columns 3.00ms 3.00ms ±0.67ms 1 +0.0%

TouchableOpacity

Scenario Mean Median StdDev Renders vs Baseline
TouchableOpacity mount 1.00ms 1.00ms ±0.00ms 1 +0.0%
TouchableOpacity unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
TouchableOpacity rerender 1.50ms 1.50ms ±0.53ms 2 +50.0%
TouchableOpacity custom-active-opacity 0.60ms 1.00ms ±0.52ms 1 +0.0%
TouchableOpacity disabled 0.80ms 1.00ms ±0.42ms 1 +0.0%
TouchableOpacity with-all-handlers 0.70ms 1.00ms ±0.48ms 1 +0.0%
TouchableOpacity with-hit-slop 1.00ms 1.00ms ±0.47ms 1 +0.0%
TouchableOpacity with-delay 0.70ms 1.00ms ±0.48ms 1 +0.0%
TouchableOpacity nested 1.50ms 1.50ms ±0.53ms 1 +50.0%
TouchableOpacity multiple-10 7.07ms 6.00ms ±1.62ms 1 +0.0%
TouchableOpacity multiple-50 33.20ms 33.00ms ±2.70ms 1 +13.8%
TouchableOpacity multiple-100 64.67ms 60.00ms ±19.24ms 1 +20.0%

ScrollView

Scenario Mean Median StdDev Renders vs Baseline
ScrollView mount 0.50ms 0.50ms ±0.53ms 1 +Infinity%
ScrollView unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
ScrollView rerender 0.50ms 0.50ms ±0.53ms 2 -50.0%
ScrollView children-20 3.47ms 3.00ms ±1.46ms 1 -25.0%
ScrollView children-100 17.20ms 17.00ms ±2.37ms 1 +6.3%
ScrollView horizontal 3.20ms 3.00ms ±0.63ms 1 -25.0%
ScrollView sticky-headers 3.50ms 4.00ms ±1.65ms 1 +33.3%
ScrollView scroll-indicators 0.90ms 1.00ms ±0.32ms 1 +0.0%
ScrollView nested 1.40ms 1.00ms ±0.70ms 1 +0.0%
ScrollView content-container-style 0.80ms 1.00ms ±0.42ms 1 +0.0%
ScrollView children-500 22.13ms 21.00ms ±3.56ms 1 +10.5%

TouchableHighlight

Scenario Mean Median StdDev Renders vs Baseline
TouchableHighlight mount 0.50ms 0.50ms ±0.53ms 1 +0.0%
TouchableHighlight unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
TouchableHighlight rerender 0.70ms 1.00ms ±0.48ms 2 +0.0%
TouchableHighlight custom-underlay-color 0.50ms 0.50ms ±0.53ms 1 +Infinity%
TouchableHighlight custom-active-opacity 0.40ms 0.00ms ±0.52ms 1 +0.0%
TouchableHighlight disabled 0.40ms 0.00ms ±0.52ms 1 +0.0%
TouchableHighlight with-all-handlers 0.40ms 0.00ms ±0.52ms 1 +0.0%
TouchableHighlight with-hit-slop 0.30ms 0.00ms ±0.48ms 1 +0.0%
TouchableHighlight nested-touchables 1.00ms 1.00ms ±0.00ms 1 +0.0%
TouchableHighlight multiple-touchables-10 2.70ms 3.00ms ±0.48ms 1 +0.0%
TouchableHighlight multiple-touchables-50 15.30ms 14.50ms ±2.31ms 1 +16.0%
TouchableHighlight multiple-touchables-100 25.20ms 25.00ms ±4.18ms 1 +11.1%

Pressable

Scenario Mean Median StdDev Renders vs Baseline
Pressable mount 0.50ms 0.50ms ±0.53ms 1 +Infinity%
Pressable unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
Pressable rerender 0.50ms 0.50ms ±0.53ms 2 +0.0%
Pressable with-all-handlers 0.50ms 0.50ms ±0.53ms 1 +Infinity%
Pressable with-style-function 0.30ms 0.00ms ±0.48ms 1 +0.0%
Pressable disabled 0.30ms 0.00ms ±0.48ms 1 +0.0%
Pressable with-hit-slop 0.40ms 0.00ms ±0.52ms 1 +0.0%
Pressable nested 0.60ms 1.00ms ±0.52ms 1 +0.0%
Pressable multiple-10 3.47ms 3.00ms ±1.06ms 1 +0.0%
Pressable multiple-50 17.27ms 17.00ms ±2.58ms 1 +21.4%
Pressable multiple-100 18.47ms 14.00ms ±10.67ms 1 +16.7%

Modal

Scenario Mean Median StdDev Renders vs Baseline
Modal mount 0.40ms 0.00ms ±0.52ms 1 +0.0%
Modal unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Modal rerender 0.50ms 0.50ms ±0.53ms 2 +Infinity%
Modal slide-animation 0.30ms 0.00ms ±0.48ms 1 +0.0%
Modal fade-animation 0.20ms 0.00ms ±0.42ms 1 +0.0%
Modal transparent 0.30ms 0.00ms ±0.48ms 1 +0.0%
Modal with-callbacks 0.40ms 0.00ms ±0.52ms 1 +0.0%
Modal rich-content 2.00ms 2.00ms ±0.00ms 1 +0.0%
Modal with-accessibility 0.30ms 0.00ms ±0.48ms 1 +0.0%

Image

Scenario Mean Median StdDev Renders vs Baseline
Image mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Image rerender 0.00ms 0.00ms ±0.00ms 2 +0.0%
Image with-resize-mode 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-border-radius 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-tint-color 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-blur-radius 0.20ms 0.00ms ±0.42ms 1 +0.0%
Image with-accessibility 0.10ms 0.00ms ±0.32ms 1 +0.0%
Image multiple-10 1.00ms 1.00ms ±0.00ms 1 +0.0%
Image multiple-50 4.00ms 4.00ms ±0.00ms 1 +33.3%
Image multiple-100 8.80ms 8.00ms ±1.57ms 1 +0.0%

ActivityIndicator

Scenario Mean Median StdDev Renders vs Baseline
ActivityIndicator mount 0.50ms 0.00ms ±1.58ms 1 +0.0%
ActivityIndicator unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
ActivityIndicator rerender 0.20ms 0.00ms ±0.42ms 2 +0.0%
ActivityIndicator size-large 0.20ms 0.00ms ±0.42ms 1 +0.0%
ActivityIndicator size-small 0.20ms 0.00ms ±0.42ms 1 +0.0%
ActivityIndicator with-color 0.10ms 0.00ms ±0.32ms 1 +0.0%
ActivityIndicator not-animating 0.10ms 0.00ms ±0.32ms 1 +0.0%
ActivityIndicator with-accessibility 0.20ms 0.00ms ±0.42ms 1 +0.0%
ActivityIndicator multiple-10 1.00ms 1.00ms ±0.00ms 1 +0.0%
ActivityIndicator multiple-50 4.07ms 4.00ms ±1.16ms 1 +0.0%
ActivityIndicator multiple-100 8.47ms 8.00ms ±1.46ms 1 +14.3%

Switch

Scenario Mean Median StdDev Renders vs Baseline
Switch mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
Switch unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
Switch rerender 0.30ms 0.00ms ±0.48ms 2 -100.0%
Switch value-true 0.40ms 0.00ms ±0.52ms 1 +0.0%
Switch disabled 0.30ms 0.00ms ±0.48ms 1 +0.0%
Switch custom-colors 0.70ms 0.00ms ±1.57ms 1 +0.0%
Switch on-value-change 0.20ms 0.00ms ±0.42ms 1 +0.0%
Switch with-accessibility 0.40ms 0.00ms ±0.52ms 1 +0.0%
Switch multiple-10 1.53ms 2.00ms ±0.52ms 1 +0.0%
Switch multiple-50 9.80ms 9.00ms ±2.81ms 1 +0.0%
Switch multiple-100 21.00ms 22.00ms ±4.17ms 1 +37.5%

Button

Scenario Mean Median StdDev Renders vs Baseline
Button mount 0.60ms 1.00ms ±0.52ms 1 +0.0%
Button unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
Button rerender 1.10ms 1.00ms ±0.74ms 2 +0.0%
Button disabled 0.60ms 1.00ms ±0.52ms 1 +0.0%
Button with-color 0.70ms 1.00ms ±0.48ms 1 +100.0%
Button with-accessibility 0.70ms 1.00ms ±0.48ms 1 +0.0%
Button multiple-10 6.67ms 6.00ms ±1.11ms 1 +0.0%
Button multiple-50 25.40ms 30.00ms ±9.05ms 1 +11.1%
Button multiple-100 23.20ms 21.00ms ±10.76ms 1 +10.5%

TextInput

Scenario Mean Median StdDev Renders vs Baseline
TextInput mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
TextInput unmount 0.10ms 0.00ms ±0.32ms 0 +0.0%
TextInput rerender 0.10ms 0.00ms ±0.32ms 2 +0.0%
TextInput multiline 0.20ms 0.00ms ±0.42ms 1 +0.0%
TextInput with-value 0.10ms 0.00ms ±0.32ms 1 +0.0%
TextInput styled 0.20ms 0.00ms ±0.42ms 1 +0.0%
TextInput multiple-100 9.60ms 10.00ms ±2.03ms 1 +42.9%

View

Scenario Mean Median StdDev Renders vs Baseline
View mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
View unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
View rerender 0.30ms 0.00ms ±0.48ms 2 +0.0%
View nested-50 3.60ms 4.00ms ±0.51ms 1 +33.3%
View nested-100 8.67ms 8.00ms ±1.88ms 1 +14.3%
View shadow 0.20ms 0.00ms ±0.42ms 1 +0.0%
View border-radius 0.10ms 0.00ms ±0.32ms 1 +0.0%
View nested-500 19.53ms 11.00ms ±17.10ms 1 +10.0%

Text

Scenario Mean Median StdDev Renders vs Baseline
Text mount 0.20ms 0.00ms ±0.42ms 1 +0.0%
Text unmount 0.00ms 0.00ms ±0.00ms 0 +0.0%
Text rerender 0.40ms 0.00ms ±0.52ms 2 +0.0%
Text long-1000 0.10ms 0.00ms ±0.32ms 1 +0.0%
Text nested 0.40ms 0.00ms ±0.52ms 1 +0.0%
Text styled 0.20ms 0.00ms ±0.42ms 1 +0.0%
Text multiple-100 8.80ms 9.00ms ±1.42ms 1 +28.6%

SectionList.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
SectionList native mount 10.23ms 10.30ms ±0.71ms 1 +58.3%

FlatList.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
FlatList native mount 7.84ms 8.35ms ±1.32ms 1 -9.6%

TouchableHighlight.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
TouchableHighlight native mount 2.16ms 1.93ms ±0.70ms 1 -7.6%

TouchableOpacity.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
TouchableOpacity native mount 2.33ms 2.19ms ±0.39ms 1 -30.2%

Pressable.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Pressable native mount 2.05ms 1.92ms ±0.33ms 1 -23.4%

ScrollView.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
ScrollView native mount 4.78ms 4.78ms ±0.75ms 1 +17.9%

ActivityIndicator.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
ActivityIndicator native mount 1.72ms 1.65ms ±0.27ms 1 -33.6%

TextInput.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
TextInput native mount 2.68ms 2.56ms ±0.67ms 1 -37.5%

Switch.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Switch native mount 1.62ms 1.48ms ±0.32ms 1 -14.4%

Button.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Button native mount 2.61ms 2.55ms ±0.44ms 1 -2.0%

Modal.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Modal native mount 1.21ms 1.18ms ±0.20ms 1 -3.3%

Image.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Image native mount 2.03ms 2.00ms ±0.21ms 1 -11.7%

View.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
View native mount 1.29ms 1.30ms ±0.11ms 1 -9.3%

Text.native-perf-test.ts

Scenario Mean Median StdDev Renders vs Baseline
Text native mount 1.65ms 1.56ms ±0.27ms 1 -10.6%

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants