question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

App crashes when exiting an app that uses MenuBar and WebView2

See original GitHub issue

Describe the bug

In an app that uses MenuBar and WebView2, if you exit the app after performing the following processing, an access violation will occur.

  1. Call WebView2.EnsureCoreWebView2Async.
  2. Add WebView2 to the UI.
  3. Remove WebView2 from the UI after WebView2 is displayed on the screen.

An access violation occurs when the “exit” function is called in “exe_common.inl”.

This issue only occurs in Windows App SDK 1.1.X and not in 1.0.3.

Steps to reproduce the bug

This problem is reproduced with a very simple code.

  1. Create a “Blank App, Packaged (WinUI 3 in Desktop)” project in Visual Studio. (Project name: App1)
  2. Update the Windows App SDK to version 1.1.0 or higher with Nuget Package Manager.
  3. Edit code

MainWindow.xaml

<Window
    x:Class="App1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <MenuBar Grid.Row="0">
            <MenuBar.Items>
                <MenuBarItem Title="File">
                    <MenuBarItem.Items>
                        <MenuFlyoutItem Text="Open" Click="OpenButtonClick" />
                    </MenuBarItem.Items>
                </MenuBarItem>
            </MenuBar.Items>
        </MenuBar>

        <Grid x:Name="Holder" Grid.Row="1" />
    </Grid>
</Window>

MainWindow.idl

namespace App1
{
    [default_interface]
    runtimeclass MainWindow : Microsoft.UI.Xaml.Window
    {
        MainWindow();
    }
}

MainWindow.xaml.h

#pragma once

#include "MainWindow.g.h"

using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::UI::Xaml;
using namespace winrt::Microsoft::UI::Xaml::Controls;

namespace winrt::App1::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
        MainWindow();

        void OpenButtonClick(IInspectable const& sender, RoutedEventArgs const& e);

        IAsyncAction ShowWebsite(WebView2 web);
    };
}

namespace winrt::App1::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}

MainWindow.xaml.cpp

#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

#include <winrt/Microsoft.Web.WebView2.Core.h>

using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::UI::Xaml;
using namespace winrt::Microsoft::UI::Xaml::Controls;
using namespace winrt::Microsoft::Web::WebView2::Core;

namespace winrt::App1::implementation
{

    MainWindow::MainWindow()
    {
        InitializeComponent();
    }

    void MainWindow::OpenButtonClick(IInspectable const& sender, RoutedEventArgs const& e) {

        Holder().Children().Clear();

        WebView2 web{};

        ShowWebsite(web);

        Holder().Children().Append(web);

    }

    IAsyncAction MainWindow::ShowWebsite(WebView2 web)
    {
        co_await web.EnsureCoreWebView2Async();

        auto core = web.CoreWebView2();
        core.Navigate(L"https://www.microsoft.com/");

        co_return;
    }

}
  1. Start Debugging (Platform: x64)
  2. Repeat “File”-> “Open” twice from the menu bar.
  3. Close the main window and exit the app.
  4. An access violation occurs. (See screenshot)

Expected behavior

No error occurs when exiting the app.

Screenshots

access_violation

NuGet package version

WinUI 3 - Windows App SDK 1.1.1

Windows app type

  • UWP
  • Win32

Device form factor

Desktop

Windows version

Windows 10 (21H2): Build 19044

Additional context

This issue does not occur if you edit the code as one of the following:

  • Do not remove WebView2 from the UI. (Do not call Holder().Children().Clear().)
  • Do not call EnsureCoreWebView2Async. (Comment out the contents of the ShowWebsite function.)
  • Replace the menu bar with an “Open” button. <Button Grid.Row="0" Click="OpenButtonClick">Open</Button>

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
namazsocommented, Aug 30, 2022

The reason behind this crash is calling into threadpoolwinrt.dll when it is already freed.

On process shutdown, dlls are unloaded in reverse order. As threadpoolwinrt.dll is loaded later than Microsoft.Ui.Xaml.dll, it gets unloaded first. During unload, it sets Microsoft::WRL::Details::ModuleBase::module_ to nullptr.

Here’s a stack trace when this happens:

threadpoolwinrt.dll!Microsoft::WRL::Module<1,Microsoft::WRL::Details::DefaultModule<1> >::~Module<1,Microsoft::WRL::Details::DefaultModule<1> >+0x1e
threadpoolwinrt.dll!Microsoft::WRL::Details::DefaultModule<1>::`vector deleting destructor'+0x14
threadpoolwinrt.dll!Microsoft::WRL::Details::StaticStorage<Microsoft::WRL::Details::DefaultModule<1>,0,int>::~StaticStorage<Microsoft::WRL::Details::DefaultModule<1>,0,int>+0x26
threadpoolwinrt.dll!CRT_INIT+0xc3
threadpoolwinrt.dll!__DllMainCRTStartup+0x1c8
ntdll.dll!LdrpCallInitRoutine+0x61
ntdll.dll!LdrShutdownProcess+0x141
ntdll.dll!RtlExitUserProcess+0xad
kernel32.dll!ExitProcessImplementation+0xb
ucrtbase.dll!exit_or_terminate_process+0x44
ucrtbase.dll!common_exit+0x6f
DuckManager.exe!__scrt_common_main_seh+0x173
kernel32.dll!BaseThreadInitThunk+0x14
ntdll.dll!RtlUserThreadStart+0x21

Followed by this, Microsoft.Ui.Xaml.dll unloads, releasing its COM references to Windows.System.Threading.ThreadPoolTimer. Stack trace:

threadpoolwinrt.dll!Microsoft::WRL::ActivationFactory<Windows::System::Threading::IThreadPoolStatics,Microsoft::WRL::FtmBase,Microsoft::WRL::Details::Nil,0>::Release+0x58
Microsoft.ui.xaml.dll!ThreadPoolService::ReleaseFactories+0x8b
Microsoft.ui.xaml.dll!DeinitializeDll+0x62
Microsoft.ui.xaml.dll!DllMain+0x39
Microsoft.ui.xaml.dll!dllmain_dispatch+0x8f
ntdll.dll!LdrpCallInitRoutine+0x61
ntdll.dll!LdrShutdownProcess+0x141
ntdll.dll!RtlExitUserProcess+0xad
kernel32.dll!ExitProcessImplementation+0xb
ucrtbase.dll!exit_or_terminate_process+0x44
ucrtbase.dll!common_exit+0x6f
DuckManager.exe!__scrt_common_main_seh+0x173
kernel32.dll!BaseThreadInitThunk+0x14
ntdll.dll!RtlUserThreadStart+0x21

However, Microsoft::WRL::ActivationFactory<Windows::System::Threading::IThreadPoolStatics,Microsoft::WRL::FtmBase,Microsoft::WRL::Details::Nil,0>::Release tries to call Microsoft::WRL::Details::ModuleBase::module_->DecrementObjectCount(void), but only when the passed object’s reference count is 0 or 1 post-dereference. On the path with 0 (1 pre-decrement), there’s a nullptr check (even though that shouldn’t happen either), however the path with 1 does not have this nullptr check, hence the crash.

This means this crash will occur any time there are two or more references to the ThreadPoolTimer interface, opened from dlls that were loaded earlier and destroyed in their destructors. Xaml keeps one on its own by default, while initializing WebView will cause a second reference, therefore fulfilling the requirements for a crash.

I created a simple C++ program and library to recreate this issue in a cleaner environment:

Dll1.cpp

// compile as dll
#include <windows.h>
#include <roapi.h>
#include <cstdio>
#include <vector>
#include <windows.system.threading.h>

#pragma comment(lib, "windowsapp.lib")

GUID GUID_1a8a9d02_e482_461b_b8c78efad1cce590 = { 0x1a8a9d02, 0xe482, 0x461b, { 0xB8, 0xC7, 0x8E, 0xFA, 0xD1, 0xCC, 0xE5, 0x90 } };
std::vector<IUnknown*> tpts;

constexpr static size_t how_many = 2; // Set to 1 to avoid crash

struct IHaveADestructor
{
  IHaveADestructor() = default;
  ~IHaveADestructor()
  {
    for (const auto tpt : tpts)
      tpt->Release();
  }
};
IHaveADestructor asdasdsa;

__declspec(dllexport) int do_stuff()
{
  RoInitialize(RO_INIT_MULTITHREADED);
  HSTRING hs;
  WindowsCreateString(
    L"Windows.System.Threading.ThreadPoolTimer",
    wcslen(L"Windows.System.Threading.ThreadPoolTimer"),
    &hs);
  for (size_t i = 0; i < how_many; ++i)
  {
    IUnknown* tpt{};
    const auto hr = RoGetActivationFactory(
      hs,
      GUID_1a8a9d02_e482_461b_b8c78efad1cce590,
      (void**)&tpt
    );
    if (!tpt)
    {
      printf("shits broken! %08X\n", hr);
      return -1;
    }
    tpts.push_back(tpt);
  }
  return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    return TRUE;
}

main.cpp

// link against the earlier dll
extern int do_stuff();

int main()
{
  do_stuff();
  return 0;
}

Setting how_many to 1 represents normal Xaml levels of incorrectness, while 2 represents the WebView scenario with two offending modules.

Unfortunately I couldn’t come up with a simple workaround, so fixing this is mostly on Microsoft.

The most obvious fix would be not calling ThreadPoolService::ReleaseFactories if deinitialization happens due to process exiting. In general it is not a good practice anyways.

0reactions
Scottj1scommented, Jan 26, 2023
Read more comments on GitHub >

github_iconTop Results From Across the Web

Power BI Desktop WebView2 crash - Page 2
Windows was trying to restart, said that it was having problems closing Power BI Desktop, clicked Cancel to manually close the apps.
Read more >
Webview2 crashes when calling document.write on newly ...
This is a bug in the WebView2 Runtime. It is fixed in versions 101.0.1210.8 and higher. See Test upcoming APIs and features for...
Read more >
Overview of WebView2 features and APIs
Communicate between native code and web code using simple messages, JavaScript code, and native objects. Browser features, The WebView2 control ...
Read more >
Xaml Islands Win32 MenuFlyoutSubItem crash
Run the app, open the menu, hover over the first SubItem until the menu animation starts playing, then quickly move to the second...
Read more >
My app crashes when closing my seccond window
My app crashes when closing my seccond window. This is all I get. No information at all. I am using webview in my...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found