Details
-
Bug
-
Resolution: Fixed
-
P2: Important
-
6.6.0
-
None
-
Dell Latitude 5521
11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz
Windows 10 Pro
OS Build 19045.3693
-
-
44f1e17d2 (dev), 073e01142 (6.7), ea027cb82 (6.6), 199ca6500 (tqtc/lts-6.5), 2964b974c (dev), b573c337a (6.7), 6e817fc7a (6.6), 2e581b275 (tqtc/lts-6.5), 5fcfa339b (dev), 2fd9cc557 (6.7), 7c3a328c0 (6.6), c8e219be2 (tqtc/lts-6.5), 7efc9f9b6 (dev)
-
Multimedia Wk 13-14
Description
Since migrating our app from Qt 5.15.14 to Qt 6.6.0, we've discovered that certain code that it usually executed during application shutdown is no longer being called. This includes:
- DllMain() functions in our DLLs that handle the DLL_PROCESS_DETACH case.
- Destructors for C++ static objects.
Normally, these calls are made as part of the Windows 'exit' processing that goes on after an application leaves its 'main' function. Windows normally unloads each DLL in turn, calling its DllMain() function, and then calls 'atexit' handlers, which includes a dynamically generated handler for each static C++ object, that runs its destructor.
Since moving to Qt 6, none of this code is executed any more - but only if our app makes use of Qt6Multimedia classes, such as QMediaPlayer. If we do use QMediaPlayer, then the process abruptly terminates before these exit steps get called.
I've been able to identify the line of code at which this termination is occurring. It's happening on the call to UnregisterEndpointNotificationCallback() in the ~QWindowsMediaDevices() destructor, in qwindowsmediadevices.cpp:
QWindowsMediaDevices::~QWindowsMediaDevices() { if (m_deviceEnumerator) { m_deviceEnumerator->UnregisterEndpointNotificationCallback(m_notificationClient.Get()); } if (m_warmUpAudioClient) { HRESULT hr = m_warmUpAudioClient->Stop(); if (FAILED(hr)) { qWarning() << "Failed to stop audio engine" << hr; } } m_deviceEnumerator.Reset(); m_notificationClient.Reset(); m_warmUpAudioClient.Reset(); CoUninitialize(); }
To reproduce this, open and build the Qt 6 media player example app at C:\Qt\Examples\Qt-6.6.0\multimedia\player. Set a breakpoint on the call to UnregisterEndpointNotificationCallback() in C:\Qt\6.6.0\Src\qtmultimedia\src\multimedia\windows\qwindowsmediadevices.cpp. When the breakpoint is reached, press F10 to step over the call. The process will immediately terminate, with no identifiable error or exception.
I'm not sure why this call to UnregisterEndpointNotificationCallback() is killing the process in this way. The code in question is being executed within a static destructor, destroying the 'devicesHolder', and the stack looks like this:
QWindowsMediaDevices::`scalar deleting destructor' - Qt6Multimediad
QWindowsMediaDevices::~QWindowsMediaDevices - qwindowsmediadevices.cpp
`anonymous namespace'::DevicesHolder::~DevicesHolder - qplatformmediadevices.cpp
`anonymous namespace'::`dynamic atexit destructor for 'devicesHolder'' - Qt6Multimediad
initterm_e - ucrtbased
initterm_e - ucrtbased
initterm_e - ucrtbased
execute_onexit_table - ucrtbased
__scrt_dllmain_uninitialize_c - utility.cpp
dllmain_crt_process_detach - dll_dllmain.cpp
dllmain_crt_dispatch - dll_dllmain.cpp
dllmain_dispatch - dll_dllmain.cpp
_DllMainCRTStartup - dll_dllmain.cpp
RtlActivateActivationContextUnsafeFast - ntdll
LdrShutdownProcess - ntdll
RtlExitUserProcess - ntdll
It may have something to do with accessing COM objects in a static destructor, but I'm not really sure.
If I debug this in Visual Studio, I can use "Set Next Statement" to skip over the call to UnregisterEndpointNotificationCallback(). It doesn't get much further if I do this - it crashes soon after on the call to m_warmUpAudioClient.Reset(). The only way I've found to avoid the crash is to use "Set Next Statement" to step over this line of code in DevicesHolder::~DevicesHolder():
delete nativeInstance;
This prevents it from executing the problematic ~QWindowsMediaDevices() destructor, and the remainder of the app exit processing occurs as it should. Of course, I can only do this in the debugger, and even if I were to actually change the code to remove that 'delete' call and rebuild the DLL, it would be introducing a memory leak.
I'd really appreciate it if someone could look into why this is happening, as the lack of normal exit handler execution in our DLLs is quite a big issue for us.
Attachments
Issue Links
- relates to
-
QTBUG-121768 Windows Media Foundation is being shut down from static destructors
- Closed
-
PYSIDE-2656 Annoying warning message only with PySide 6.6.3
- Closed
-
QTBUG-124577 Don't use QtGlobalStatic::ApplicationHolder directly in Qt Multimedia
- Closed