Guard island input site lookup during shutdown - #11654
Conversation
CDependencyObject::GetElementIslandInputSite() called CCoreServices::GetInputServices()->GetPrimaryRegisteredIslandInputSite() without checking the result of GetInputServices(). By the time a focused TextBox is torn down during framework shutdown the input services are already gone, so the call runs on a null "this" and faults while reading m_islandInputSiteRegistrations. Null-check core services and input services and return nullptr instead. Every caller already funnels the result through CInputServices::GetUnderlyingInputHwndFromIslandInputSite(), which is declared _In_opt_ and null-checks its argument, so "no island input site" is already an expected result. Carries forward the fix proposed by @jonwis in microsoft#11063, rebased onto the current dxaml/ layout.
|
Some context on where this came from, since I don't want to take more credit than I'm due. I hit this crash while working on my own app. The digging that followed — narrowing it down to a focused text input at teardown, building the minimal repro, re-testing it across 1.7 through 2.4.0, and reading through the callers to check that a null return is actually safe — was done with a lot of help from coding agents. The write-up in #11653 and the verification tables here are mostly the product of that, not of me reading the XAML core by hand. The fix itself is Jon's, from #11063. I rebased it onto the current layout and wrote it up, but I didn't come up with it. So this is his fix, my app's crash and repro, and a fair amount of agent-assisted legwork — rather than my work alone. Flagging it so nobody reviews it under the wrong assumption about where the confidence in it comes from. |
Godly T.Alias (godlytalias)
left a comment
There was a problem hiding this comment.
A fix was done for the same issue, 691c6a7
Please check whether the crash gets fixed with the same
If these changes both had test coverage, we'd know right away. Is it possible to add a test for this? |
|
Godly T.Alias (@godlytalias) thanks for digging that one up, I hadn't found it. I tested against the newest bits I could get from NuGet, including If you can point me at a build that definitely contains it, I'll happily test against that and report back here. |
|
Jesse Collins (@JesseCol) agreed, test coverage would settle this straight away rather than us comparing two fixes by hand. Let me have a look at what's possible there and come back to you. |
essam Jesse Collins (@JesseCol) yeah, the fix was not serviced in any of the recent updates of winappsdk. I am trying to repro the same issue locally from main (which contains the prior fix I did). Will keep you guys posted on the same by EOD, if the prior fix already has the issue mitigated, I will add a test for it to confirm and close this. Meanwhile I will also service it for September release. |
Also thanks Essam (@TheBlueSky) for taking the time and initiative to file the issue and contribute for the fix, much appreciated! |
Repro'd: Closing the window with a TextBox focused AV 0xC0000005 in CInputServices::GetPrimaryRegisteredIslandInputSite during shutdown Issue is already fixed with 691c6a7 on main . Without the above fix CCoreServices::~CCoreServices was nulling m_inputServices before delete m_pTextCore. with the fix (moving the reset to after the text core is torn down) we dont see it main. Essam (@TheBlueSky) I will service the fix in next servicing release (ETA September end) and will also add a test for this scenario in main, your diagnosis was on point, and the repro was genuinely useful in confirming the servicing gap. |
Fixes
Fixes #11653
PR Type
Description
Carries forward Jon Wiswall (@jonwis)'s fix from #11063, rebased onto the current
dxaml/layout (that PR still patches the oldsrc/dxaml/...path, so it no longer applies). Credit for the diagnosis and the fix is his — I hit the same crash independently and he suggested opening a fresh issue and PR to move it to completion.CDependencyObject::GetElementIslandInputSite()dereferenced the result ofCCoreServices::GetInputServices()without a null check:During framework shutdown the input services are already gone, so this runs
GetPrimaryRegisteredIslandInputSite()on a nullthisand faults while readingm_islandInputSiteRegistrations. Tearing down a focusedTextBoxreaches it viaCTextBoxBase::Destroy→ the RichEdit gripper code →TextServicesHost::TxGetWindow.This PR null-checks core services and input services and returns
nullptrinstead. It also adds the matchingcoreServices &&guard on theHasXamlIslandRoots()call above, as in the original PR.Returning null is safe because it is already the contract: every caller of
GetElementIslandInputSite()funnels the result intoCInputServices::GetUnderlyingInputHwndFromIslandInputSite(), which is declared_In_opt_and null-checks its argument before use.GetPrimaryRegisteredIslandInputSite()itself already returnsnullptrwhen no island input sites are registered, so callers must handle null regardless.Current Behavior
Closing a window while a
TextBoxhas focus crashes the process with0xC0000005insideMicrosoft.UI.Xaml.dllduring shutdown. Reproduces 3/3 on 1.7.260224002, 1.8.260317003, 1.8.260804001 and 2.4.0 (details and a minimal repro in the linked issue).New Behavior
The lookup returns
nullptrwhen there is no input site left to return, callers treat that as "no input hwnd" as they already do, and the app exits cleanly with exit code 0.Customer Impact
User-facing. Any app that leaves a text input focused when the window closes currently dies with an access violation instead of exiting cleanly. It is invisible to the user mid-session but logs an Application Error / WER crash on every exit, drowning real crashes in telemetry and breaking any work that depends on a clean shutdown.
Regression Potential
The change only alters behaviour on paths that dereference a null pointer today, i.e. paths that currently crash. When core services and input services are alive the behaviour is byte-for-byte identical.
One caveat carried over from #11063: Jon Wiswall (@jonwis) noted that all callsites handle a null return except DirectManipulation. The DManip path goes through
CInputServices::GetIslandInputSiteRegistrationForUIElement(), whichFAIL_FAST_IFs on a missing registration but does not callGetElementIslandInputSite(), so it is not reached by this change. Worth a second pair of eyes from someone who owns that area.Testing
I tried to validate this with a local build and could not get there.
init.cmd amd64chkcompletes fine, butbuild.cmd mux /i amd64chkfails inXamlCompilerPrerequisites.slnwithMSB8040— Spectre-mitigated libraries are required — formanifest.vcxproj,gencompheadersandidl.vcxprojandgenmrtheadersandidl.vcxproj. Neither toolset on this machine ships them (VS 2022 14.44 or VS 2026 14.51), and settingSpectreMitigation=falsein the environment does not override it for those three projects even thougheng/common.propsguards the property. Two notes in passing, in case they are useful: the build selected the VS 2026 MSBuild whileOneTimeSetup.cmdis documented as assuming VS 2022, andGettingStarted.mdsays CI builds are not supported yet, so I do not know whether this PR gets an automated build.So to be clear about what is and is not verified: the change is a null check applied to the current source and checked by reading every caller, not by compiling. Happy to install the
.vsconfigcomponents and retry if you would like a local build result before this merges.Verified against shipped binaries that the bug is still live and that the behaviour is exactly what the guard addresses:
TextBoxfocused at close0xC0000005TextBoxnever focusedAppWindow.Closing