From a00bff65257c603a22163b04971d0286692eff9a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 6 Nov 2024 09:21:28 -0800 Subject: [PATCH] Add a way to access QCoreApplication's instance atomically We use it from many places in Qt that may run before QCoreApplication has been created (officially not supported but it happens) and after it has been destroyed. In particular, we have code in QtDBus that runs in another thread after QCoreApplication has been destroyed and uses the event system. Accessing QCoreApplication::self anywhere but the main thread was a race condition in those conditions. Change-Id: If4ad1af9301dca98ba69fffdf88c63b220db53ac Reviewed-by: Ivan Solovev (cherry picked from commit 7d92ecd9173a5ce4af8eb6ac05d6e7648d433db4) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qcoreapplication.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index ba069c40408..b3ae47d0c81 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -140,6 +140,11 @@ extern QString qAppFileName(); Q_CONSTINIT bool QCoreApplicationPrivate::setuidAllowed = false; +Q_CONSTINIT QCoreApplication *QCoreApplication::self = nullptr; +Q_CONSTINIT static QBasicAtomicPointer g_self = nullptr; +# undef qApp +# define qApp g_self.loadRelaxed() + #if !defined(Q_OS_WIN) #ifdef Q_OS_DARWIN QString QCoreApplicationPrivate::infoDictionaryStringProperty(const QString &propertyName) @@ -199,7 +204,7 @@ Q_CONSTINIT QString *QCoreApplicationPrivate::cachedApplicationFilePath = nullpt bool QCoreApplicationPrivate::checkInstance(const char *function) { - bool b = (QCoreApplication::self != nullptr); + bool b = (qApp != nullptr); if (!b) qWarning("QApplication::%s: Please instantiate the QApplication object first", function); return b; @@ -359,7 +364,6 @@ Q_CONSTINIT QAbstractEventDispatcher *QCoreApplicationPrivate::eventDispatcher = #endif // QT_NO_QOBJECT -Q_CONSTINIT QCoreApplication *QCoreApplication::self = nullptr; Q_CONSTINIT uint QCoreApplicationPrivate::attribs = (1 << Qt::AA_SynthesizeMouseForUnhandledTouchEvents) | (1 << Qt::AA_SynthesizeMouseForUnhandledTabletEvents); @@ -861,6 +865,7 @@ void Q_TRACE_INSTRUMENT(qtcore) QCoreApplicationPrivate::init() Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object"); QCoreApplication::self = q; + g_self.storeRelaxed(q); #if QT_CONFIG(thread) #ifdef Q_OS_WASM @@ -962,6 +967,7 @@ QCoreApplication::~QCoreApplication() qt_call_post_routines(); self = nullptr; + g_self.storeRelaxed(nullptr); #ifndef QT_NO_QOBJECT QCoreApplicationPrivate::is_app_closing = true; QCoreApplicationPrivate::is_app_running = false; @@ -1140,7 +1146,7 @@ void QCoreApplication::setQuitLockEnabled(bool enabled) bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) { bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication(); - if (selfRequired && !self) + if (selfRequired && !qApp) return false; // Make it possible for Qt Script to hook into events even @@ -1165,7 +1171,7 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) if (threadData->thread.loadRelaxed() != QCoreApplicationPrivate::mainThread()) return false; #endif - return self->notify(receiver, event); + return qApp->notify(receiver, event); } /*! @@ -1294,7 +1300,7 @@ bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiv bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) { if ((receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() != mainThread() - || receiver != QCoreApplication::instance()) + || receiver != qApp) && receiver->d_func()->extraData) { for (qsizetype i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) { QObject *obj = receiver->d_func()->extraData->eventFilters.at(i);