From 81a7a4c2d94fca6fc595dcb147831b9585eaee5f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 24 Mar 2025 17:07:07 -0700 Subject: [PATCH] QThreadStorage: ensure global static exists when finish() is called MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the thread that calls ::exit() (usually, the main thread). Otherwise, depending on construction order, it is possible for the QThreadStorage's destructor list to have been destroyed by the time destroy_current_thread_data() → QThreadData::finish() calls our finish(). Fixes: QTBUG-135044 Pick-to: 6.9 6.8 Change-Id: Ic5a10367ff31e7faa039fffdc2067eba9642fbf9 Reviewed-by: Fabian Kosmale --- src/corelib/CMakeLists.txt | 2 +- src/corelib/thread/qthread_p.h | 17 ++++++++-------- src/corelib/thread/qthread_unix.cpp | 1 + src/corelib/thread/qthread_win.cpp | 1 + src/corelib/thread/qthreadstorage.cpp | 8 ++++++++ src/corelib/thread/qthreadstorage_p.h | 29 +++++++++++++++++++++++++++ 6 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 src/corelib/thread/qthreadstorage_p.h diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 23cafd2be17..38cca5a9682 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -748,7 +748,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_thread thread/qreadwritelock.cpp thread/qreadwritelock_p.h thread/qsemaphore.cpp thread/qsemaphore.h thread/qthreadpool.cpp thread/qthreadpool.h thread/qthreadpool_p.h - thread/qthreadstorage.cpp + thread/qthreadstorage.cpp thread/qthreadstorage_p.h ) qt_internal_extend_target(Core CONDITION QT_FEATURE_thread AND UNIX diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 35c5d7c7c76..b34336d7e16 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -17,18 +17,19 @@ // // -#include "qplatformdefs.h" #include "QtCore/qthread.h" -#include "QtCore/qmutex.h" -#include "QtCore/qstack.h" -#if QT_CONFIG(thread) -#include "QtCore/qwaitcondition.h" -#endif -#include "QtCore/qmap.h" + #include "QtCore/qcoreapplication.h" #include "private/qobject_p.h" +#include "QtCore/qmap.h" +#include "QtCore/qmutex.h" +#include "QtCore/qstack.h" + +#if QT_CONFIG(thread) +#include "private/qthreadstorage_p.h" +#include "QtCore/qwaitcondition.h" +#endif -#include #include QT_BEGIN_NAMESPACE diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index c19390e16b5..1710aecb8d6 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -223,6 +223,7 @@ struct QThreadDataDestroyer } struct EarlyMainThread { + EarlyMainThread() { QThreadStoragePrivate::init(); } ~EarlyMainThread() { // running function-local destructors upon ::exit() diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 77868b13a04..746231b359e 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -82,6 +82,7 @@ static void set_thread_data(QThreadData *data) noexcept { if (data) { struct Cleanup { + Cleanup() { QThreadStoragePrivate::init(); } ~Cleanup() { destroy_current_thread_data(currentThreadData); } }; static thread_local Cleanup currentThreadCleanup; diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp index 0deff1b19d9..d7f4b560a53 100644 --- a/src/corelib/thread/qthreadstorage.cpp +++ b/src/corelib/thread/qthreadstorage.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qthreadstorage.h" +#include "qthreadstorage_p.h" #include "private/qcoreapplication_p.h" #include "qthread.h" @@ -133,6 +134,13 @@ void **QThreadStorageData::set(void *p) return &value; } +void QThreadStoragePrivate::init() +{ + // Make sure the Q_GLOBAL_STATIC is initialized, ensuring consistent + // destruction order. + destructors(); +} + void QThreadStorageData::finish(void **p) { QList *tls = reinterpret_cast *>(p); diff --git a/src/corelib/thread/qthreadstorage_p.h b/src/corelib/thread/qthreadstorage_p.h new file mode 100644 index 00000000000..d73b5a1d8e5 --- /dev/null +++ b/src/corelib/thread/qthreadstorage_p.h @@ -0,0 +1,29 @@ +// Copyright (C) 2025 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTHREADSTORAGE_P_H +#define QTHREADSTORAGE_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 +#include + +QT_BEGIN_NAMESPACE + +namespace QThreadStoragePrivate { +void init(); +} // namespace QThreadStoragePrivate + +QT_END_NAMESPACE + +#endif // QTHREADSTORAGE_P_H