Skip to content

Fix DesktopWindowXamlSource related crashes when closing a window#15338

Merged
microsoft-github-policy-service[bot] merged 3 commits intomainfrom
dev/lhecker/xaml-source-close-crash
May 15, 2023
Merged

Fix DesktopWindowXamlSource related crashes when closing a window#15338
microsoft-github-policy-service[bot] merged 3 commits intomainfrom
dev/lhecker/xaml-source-close-crash

Conversation

@lhecker
Copy link
Member

@lhecker lhecker commented May 12, 2023

XAML/WinUI may pump the event loop internally. One of the functions
that does this right now is DesktopWindowXamlSource::Close().

This is problematic in the previous code, because we'd set _window
to nullptr before calling Close() and so any of the IslandWindow
callbacks may be invoked during shutdown, which then try to potentially
access _window and end up crashing. This commit fixes the issue by
simply not nulling out the _window and calling Close() directly.

Furthermore, NonClientIslandWindow may directly access WinUI
objects in its message handlers which also crashes.

I've had this happen roughly ~1% of my test exits in a debug build
and every single time on a (artificial) very slow CPU.

Validation Steps Performed

  • Closing a window destroys the rendering instance ✅

@lhecker lhecker added Issue-Bug It either shouldn't be doing this or needs an investigation. Area-UserInterface Issues pertaining to the user interface of the Console or Terminal Product-Terminal The new Windows Terminal. Priority-3 A description (P3) labels May 12, 2023
Comment on lines -77 to -79
// _window callbacks don't need to be treated this way, because:
// * IslandWindow isn't a WinRT type (so it doesn't have neat revokers like this)
// * This particular bug scenario applies when we've already freed the window.
Copy link
Member Author

Choose a reason for hiding this comment

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

In short, these 3 lines are wrong. 😄

{
_showHideWindowThrottler->Run(args.ShowOrHide());
}
_showHideWindowThrottler->Run(args.ShowOrHide());
Copy link
Member Author

@lhecker lhecker May 12, 2023

Choose a reason for hiding this comment

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

This if check is a common pattern we got with our throttled funcs. It's generally not very safe, because it fails to work as soon as Run() is called from a background thread. This code still works correctly, because the _revokers are nulled out before the _showHideWindowThrottler is reset.

@lhecker lhecker force-pushed the dev/lhecker/xaml-source-close-crash branch from fa31979 to 0801694 Compare May 12, 2023 14:34
// - args: the arguments specifying how to set the display status to ShowWindow for our window handle
winrt::fire_and_forget TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
{
co_await resume_foreground(Dispatcher());
Copy link
Member Author

Choose a reason for hiding this comment

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

With the if check for _showHideWindowThrottler removed, we can safely drop this resume_foreground. It's also a nice safety fix, because it doesn't hold onto this strongly.

@lhecker lhecker force-pushed the dev/lhecker/xaml-source-close-crash branch from 0801694 to 6b73290 Compare May 12, 2023 14:51
@lhecker lhecker changed the title Fix a rare crash when closing a window Fix DesktopWindowXamlSource related crashes when closing a window May 12, 2023
Comment on lines +31 to +34
// Avoid further callbacks into XAML/WinUI-land after we've Close()d the DesktopWindowXamlSource
// inside `IslandWindow::Close()`. XAML thanks us for doing that by not crashing. Thank you XAML.
SetWindowLongPtr(_dragBarWindow.get(), GWLP_USERDATA, 0);
IslandWindow::Close();
Copy link
Member Author

Choose a reason for hiding this comment

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

Without this, NonClientIslandWindow would crash here every single time I close a window:

const auto buttonWidthInDips{ _titlebar.CaptionButtonWidth() };

// - sender (not used)
// - args: the arguments specifying how to set the display status to ShowWindow for our window handle
winrt::fire_and_forget TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
void TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
Copy link
Member

Choose a reason for hiding this comment

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

note that changing this from a coroutine means that the excess copies on the arguments are not required. you could change them to const&

@lhecker lhecker added the AutoMerge Marked for automatic merge by the bot when requirements are met label May 15, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot enabled auto-merge (squash) May 15, 2023 13:36
@microsoft-github-policy-service microsoft-github-policy-service bot deleted the dev/lhecker/xaml-source-close-crash branch May 15, 2023 14:11
// - sender (not used)
// - args: the arguments specifying how to set the display status to ShowWindow for our window handle
void TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
void TerminalPage::_ShowWindowChangedHandler(const IInspectable& /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
Copy link
Member

Choose a reason for hiding this comment

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

you only fixed the first arg..!

DHowett pushed a commit that referenced this pull request May 15, 2023
…5338)

XAML/WinUI may pump the event loop internally. One of the functions
that does this right now is `DesktopWindowXamlSource::Close()`.

This is problematic in the previous code, because we'd set `_window`
to `nullptr` before calling `Close()` and so any of the `IslandWindow`
callbacks may be invoked during shutdown, which then try to potentially
access `_window` and end up crashing. This commit fixes the issue by
simply not nulling out the `_window` and calling `Close()` directly.

Furthermore, `NonClientIslandWindow` may directly access WinUI
objects in its message handlers which also crashes.

I've had this happen roughly ~1% of my test exits in a debug build
and every single time on a (artificial) very slow CPU.

## Validation Steps Performed
* Closing a window destroys the rendering instance ✅

(cherry picked from commit ba39db5)
Service-Card-Id: 89191262
Service-Version: 1.18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-UserInterface Issues pertaining to the user interface of the Console or Terminal AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-3 A description (P3) Product-Terminal The new Windows Terminal.

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

3 participants