Skip to content

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

Open
FaithfulAudio wants to merge 1 commit into
microsoft:mainfrom
FacilitronWorks:fix/pointer-capture-null-guard-main
Open

fix(pointer): crash (0xc0000005) when the pointer-capturing component has been unmounted#16337
FaithfulAudio wants to merge 1 commit into
microsoft:mainfrom
FacilitronWorks:fix/pointer-capture-null-guard-main

Conversation

@FaithfulAudio

@FaithfulAudio FaithfulAudio commented Jul 26, 2026

Copy link
Copy Markdown

Problem

A Fabric/Composition app crashes with an access violation (0xc0000005) during ordinary list interaction on a touch device: pan a virtualized list so the row currently holding pointer capture is recycled, then press or release again.

Root cause

Both capture paths in CompositionEventHandler look the capturing component up by its cached tag and 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, and the call dereferences it. The same unguarded pattern appears in CapturePointer (when a new capture displaces a previous one) and releasePointerCapture.

Fix

Null-check targetComponentView before notifying, at both sites. When the view is gone there is nothing to notify — CapturePointer overwrites the stale tag immediately below, and releasePointerCapture clears it via the existing m_capturedPointers.empty() branch. One file, no header or API change.

Validation

  • Root-caused and fixed in a production RNW 0.83.2 new-arch app (Facilitron FIT), compiled from source (UseExperimentalNuget=false). Before: panning the FIT inspection list and interacting with a recycled row terminated the process with 0xc0000005, reproducibly. After: an automated soak drove the guarded paths with real PT_TOUCH contacts (InjectTouchInput) — 10 press-a-row-then-pan-far-while-held events (the exact recycle-under-capture sequence), plus expand/collapse mount churn and hard flicks — with no crash and the process responsive throughout.
  • Honest limit: the binary under test already contained the guard, so the soak is consistent with the fix but does not prove causation (that would need an otherwise-identical unguarded build). The root cause is plain from the code above.
  • Not verified on this branch: no CI has run (gated behind a maintainer /azp run), and I have not built main with this change. The guard is context-adapted to main (m_capturedPointers.insert / .empty()), diff verified against main at c69cf55.

Caveats for reviewers:

🤖 Generated with Claude Code

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.empty()
branch.

main twin of microsoft#16334 (0.83-stable).
@FaithfulAudio
FaithfulAudio requested a review from a team as a code owner July 26, 2026 07:06
@azure-pipelines

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

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.

1 participant