summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Buhr <andreas@andreasbuhr.de>2022-06-15 16:14:47 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-10-31 11:02:42 +0000
commit7b7c9c699633eeca992da5409158bc29ac2635e6 (patch)
treee3582b5452f58b84ef6c904de1769eb81415ac40
parentebd259fbbe8280364e6cdb8d393e4ae390ea71eb (diff)
Proper clearing of WinRT factory cache
If we use winrt's factories we have to make sure to to clear the factory cache when one of our dlls is unloaded or we will run into dangling factory entries which might result in crashes. So we have to make sure that winrt::clear_factory_cache is called on every dll unload. In order not to increase compile times and dependencies too much qfactorycacheregistration_p.h needs to be included in Qt code whenever we use winrt's factory cache. A rule of thumb being: Include qfactorycacheregistration_p.h whenever including winrt/base.h. Other Qt modules which use winrt's factories need to be updated too. Fixes: QTBUG-103611 Change-Id: I7ab24e4b18bffaca653c5b7f56a66ce99212e339 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit ffb9dee1b0954e4d4f9e9791175609a80ecafc31) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/corelib/CMakeLists.txt6
-rw-r--r--src/corelib/configure.cmake2
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration.cpp53
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration_p.h52
-rw-r--r--src/corelib/text/qlocale_win.cpp1
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp1
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h1
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp7
-rw-r--r--tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp15
9 files changed, 136 insertions, 2 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index cf408ad28e..3dd7d47394 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -973,6 +973,12 @@ qt_internal_extend_target(Core CONDITION ANDROID
platform/android/qandroidnativeinterface.cpp
)
+qt_internal_extend_target(Core CONDITION WIN32
+ SOURCES
+ platform/windows/qfactorycacheregistration_p.h
+ platform/windows/qfactorycacheregistration.cpp
+)
+
qt_internal_extend_target(Core CONDITION HAIKU AND NOT ANDROID
SOURCES
io/qstandardpaths_haiku.cpp
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 183decb530..1ce685170a 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -743,7 +743,7 @@ qt_feature("xmlstream" PUBLIC
LABEL "XML Streaming APIs"
PURPOSE "Provides a simple streaming API for XML."
)
-qt_feature("cpp-winrt" PRIVATE
+qt_feature("cpp-winrt" PRIVATE PUBLIC
LABEL "cpp/winrt base"
PURPOSE "basic cpp/winrt language projection support"
CONDITION WIN32 AND TEST_cpp_winrt
diff --git a/src/corelib/platform/windows/qfactorycacheregistration.cpp b/src/corelib/platform/windows/qfactorycacheregistration.cpp
new file mode 100644
index 0000000000..6bd69c66d1
--- /dev/null
+++ b/src/corelib/platform/windows/qfactorycacheregistration.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qfactorycacheregistration_p.h"
+
+#include <QtCore/QMutex>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
+
+static QBasicMutex registrationMutex;
+static detail::QWinRTFactoryCacheRegistration *firstElement;
+
+detail::QWinRTFactoryCacheRegistration::QWinRTFactoryCacheRegistration(
+ QFunctionPointer clearFunction)
+ : m_clearFunction(clearFunction)
+{
+ QMutexLocker lock(&registrationMutex);
+
+ // forward pointers
+ m_next = std::exchange(firstElement, this);
+
+ // backward pointers
+ m_prevNext = &firstElement;
+ if (m_next)
+ m_next->m_prevNext = &m_next;
+}
+
+detail::QWinRTFactoryCacheRegistration::~QWinRTFactoryCacheRegistration()
+{
+ QMutexLocker lock(&registrationMutex);
+
+ *m_prevNext = m_next;
+
+ if (m_next)
+ m_next->m_prevNext = m_prevNext;
+}
+
+void detail::QWinRTFactoryCacheRegistration::clearAllCaches()
+{
+ QMutexLocker lock(&registrationMutex);
+
+ detail::QWinRTFactoryCacheRegistration *element;
+
+ for (element = firstElement; element != nullptr; element = element->m_next) {
+ element->m_clearFunction();
+ }
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/platform/windows/qfactorycacheregistration_p.h b/src/corelib/platform/windows/qfactorycacheregistration_p.h
new file mode 100644
index 0000000000..db1582e94b
--- /dev/null
+++ b/src/corelib/platform/windows/qfactorycacheregistration_p.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFACTORYCACHEREGISTRATION_P_H
+#define QFACTORYCACHEREGISTRATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#if !defined(QT_BOOTSTRAPPED) && defined(Q_OS_WIN) && !defined(Q_CC_CLANG) && QT_CONFIG(cpp_winrt)
+# define QT_USE_FACTORY_CACHE_REGISTRATION
+#endif
+
+#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
+
+#include <winrt/base.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace detail {
+
+class QWinRTFactoryCacheRegistration
+{
+public:
+ Q_CORE_EXPORT explicit QWinRTFactoryCacheRegistration(QFunctionPointer clearFunction);
+ Q_CORE_EXPORT ~QWinRTFactoryCacheRegistration();
+ Q_CORE_EXPORT static void clearAllCaches();
+
+ Q_DISABLE_COPY_MOVE(QWinRTFactoryCacheRegistration)
+private:
+ QWinRTFactoryCacheRegistration **m_prevNext = nullptr;
+ QWinRTFactoryCacheRegistration *m_next = nullptr;
+ QFunctionPointer m_clearFunction;
+};
+
+inline QWinRTFactoryCacheRegistration reg([]() noexcept { winrt::clear_factory_cache(); });
+}
+
+QT_END_NAMESPACE
+
+#endif
+#endif // QFACTORYCACHEREGISTRATION_P_H
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index d395b1f0cd..cb7131667c 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -19,6 +19,7 @@
#if QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG)
# include <winrt/base.h>
+# include <QtCore/private/qfactorycacheregistration_p.h>
// Workaround for Windows SDK bug.
// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47
namespace winrt::impl
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
index 72023c6628..5af75a89d5 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
@@ -5,6 +5,7 @@
#ifdef SUPPORTS_WINRT
#include <winrt/base.h>
+#include <QtCore/private/qfactorycacheregistration_p.h>
// Workaround for Windows SDK bug.
// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47
namespace winrt::impl
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
index cf9a08ca84..b82d123fa4 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
@@ -21,6 +21,7 @@
#ifdef SUPPORTS_WINRT
#include <winrt/base.h>
+#include <QtCore/private/qfactorycacheregistration_p.h>
#endif
using namespace Microsoft::WRL;
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index b52d624a76..2be6625833 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -45,6 +45,7 @@
#include <QtCore/qscopedpointer.h>
#include <QtCore/quuid.h>
#include <QtCore/private/qwinregistry_p.h>
+#include <QtCore/private/qfactorycacheregistration_p.h>
#include <QtGui/private/qwindowsguieventdispatcher_p.h>
@@ -221,8 +222,12 @@ QWindowsContext::~QWindowsContext()
DestroyWindow(d->m_powerDummyWindow);
unregisterWindowClasses();
- if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE)
+ if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) {
+#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
+ detail::QWinRTFactoryCacheRegistration::clearAllCaches();
+#endif
OleUninitialize();
+ }
d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows.
if (d->m_displayContext)
diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
index ee8f03d1af..afcecd4637 100644
--- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
+++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
@@ -128,6 +128,7 @@ private slots:
void wheelEventPropagation();
void qtbug_12673();
+ void qtbug_103611();
void noQuitOnHide();
void globalStaticObjectDestruction(); // run this last
@@ -2513,6 +2514,20 @@ void tst_QApplication::qtbug_12673()
#endif
}
+void tst_QApplication::qtbug_103611()
+{
+ {
+ int argc = 0;
+ QApplication app(argc, nullptr);
+ auto ll = QLocale().uiLanguages();
+ }
+ {
+ int argc = 0;
+ QApplication app(argc, nullptr);
+ auto ll = QLocale().uiLanguages();
+ }
+}
+
class NoQuitOnHideWidget : public QWidget
{
Q_OBJECT