summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qthread.cpp
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2025-04-11 11:29:28 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2025-04-11 22:24:06 +0200
commitb8de5ad1edd7e693251e5993774e78734f304100 (patch)
tree5d9e32ea1d7a5bb0a21ea079c881a7f2cca756f1 /src/corelib/thread/qthread.cpp
parent96ef0004111b47cec239846b169942bbc885c181 (diff)
QThread: explicitly clear posted events during destruction
So far, we have been destroying pending posted events during thread shutdown only as part of ~QThreadData. QThreadData is reference counted, and ~QThreadPrivate releases the reference count. However, any QObject living in a thread also holds a reference to the QThreadData. If any of those objects are only destroyed when a posted event is processed, then we have a cyclic reference problem. This might be a problem with DeferredDelete events that are posted after a QThread has exited its event loop. It does manifest as a problem with QSingleShotTimer, which is temporarily owned by a posted event object. As long as that event object is in the queue, the reference count of QThreadData never drops to zero as the QSST instance holds a reference. So the event never gets destroyed, and we end up leaking both. To fix this, explicitly clear all pending posted events during QThread destruction as well, not only during QThreadData destruction. Once the QThread is destroyed, nothing will process those events. We still clear the posted events during QThreadData destruction, as QThreadData might get destroyed when other objects release their reference count on it. This fixes a somewhat contrived problem in our test scenario, and the change is not without risk, so not cherry-picking this to any stable branch. Change-Id: I488c1d3137ce83f1c34596e1041c22759825be18 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/thread/qthread.cpp')
-rw-r--r--src/corelib/thread/qthread.cpp14
1 files changed, 10 insertions, 4 deletions
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 571fc015bb6..f94e5db1538 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -65,16 +65,21 @@ QThreadData::~QThreadData()
thread.storeRelease(nullptr);
delete t;
- for (qsizetype i = 0; i < postEventList.size(); ++i) {
- const QPostEvent &pe = postEventList.at(i);
+ clearEvents();
+
+ // fprintf(stderr, "QThreadData %p destroyed\n", this);
+}
+
+void QThreadData::clearEvents()
+{
+ for (const auto &pe : std::as_const(postEventList)) {
if (pe.event) {
pe.receiver->d_func()->postedEvents.fetchAndSubRelaxed(1);
pe.event->m_posted = false;
delete pe.event;
}
}
-
- // fprintf(stderr, "QThreadData %p destroyed\n", this);
+ postEventList.clear();
}
QAbstractEventDispatcher *QThreadData::createEventDispatcher()
@@ -168,6 +173,7 @@ QThreadPrivate::~QThreadPrivate()
// unless there is already a potential use-after-free bug, as the
// thread is in the process of being destroyed
delete m_statusOrPendingObjects.list();
+ data->clearEvents();
data->deref();
}