diff options
| author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2025-04-11 11:29:28 +0200 |
|---|---|---|
| committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2025-04-11 22:24:06 +0200 |
| commit | b8de5ad1edd7e693251e5993774e78734f304100 (patch) | |
| tree | 5d9e32ea1d7a5bb0a21ea079c881a7f2cca756f1 /src/corelib/thread/qthread.cpp | |
| parent | 96ef0004111b47cec239846b169942bbc885c181 (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.cpp | 14 |
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(); } |
