From 2d92ea02501c058f55a8562f55804ccb105bf4bf Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 4 Aug 2025 16:28:53 +0200 Subject: QProperty: Avoid referencing stale QBindingStatus Because we cache the QBindingStatus in QObjects, and the QObjects might outlive the native thread, we can't bind the lifetime of the QBindingStatus solely to the native thread. Instead, keep it alive while the QThreadData associated with the QObject still exists. This is done by moving the BindingStatusOrList member for QThreadPrivate to QThreadData, and by letting QThreadData own the binding status. Pick-to: 6.10 6.9 6.8 6.5 Fixes: QTBUG-126134 Change-Id: I747ec1778f6b6f376c38d1c678dc5b2f62fcb7ef Reviewed-by: Ivan Solovev Reviewed-by: Ulf Hermann --- src/corelib/thread/qthread.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/corelib/thread/qthread.cpp') diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 3160ee27c37..553b38fec8f 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -118,7 +118,7 @@ QAdoptedThread::QAdoptedThread(QThreadData *data) #if QT_CONFIG(thread) d_func()->threadState = QThreadPrivate::Running; init(); - d_func()->m_statusOrPendingObjects.setStatusAndClearList( + d_func()->data->m_statusOrPendingObjects.setStatusAndClearList( QtPrivate::getBindingStatus({})); #endif // fprintf(stderr, "new QAdoptedThread = %p\n", this); @@ -173,7 +173,7 @@ QThreadPrivate::~QThreadPrivate() // access to m_statusOrPendingObjects cannot race with anything // unless there is already a potential use-after-free bug, as the // thread is in the process of being destroyed - delete m_statusOrPendingObjects.list(); + delete data->m_statusOrPendingObjects.list(); data->clearEvents(); data->deref(); } @@ -625,7 +625,6 @@ QThread::QualityOfService QThread::serviceLevel() const */ void QtPrivate::BindingStatusOrList::setStatusAndClearList(QBindingStatus *status) noexcept { - if (auto pendingObjects = list()) { for (auto obj: *pendingObjects) QObjectPrivate::get(obj)->reinitBindingStorageAfterThreadMove(); @@ -654,7 +653,7 @@ int QThread::exec() const auto status = QtPrivate::getBindingStatus(QtPrivate::QBindingStatusAccessToken{}); QMutexLocker locker(&d->mutex); - d->m_statusOrPendingObjects.setStatusAndClearList(status); + d->data->m_statusOrPendingObjects.setStatusAndClearList(status); d->data->quitNow = false; if (d->exited) { d->exited = false; @@ -708,18 +707,18 @@ void QtPrivate::BindingStatusOrList::removeObject(QObject *object) QBindingStatus *QThreadPrivate::addObjectWithPendingBindingStatusChange(QObject *obj) { - if (auto status = m_statusOrPendingObjects.bindingStatus()) + if (auto status = data->m_statusOrPendingObjects.bindingStatus()) return status; QMutexLocker lock(&mutex); - return m_statusOrPendingObjects.addObjectUnlessAlreadyStatus(obj); + return data->m_statusOrPendingObjects.addObjectUnlessAlreadyStatus(obj); } void QThreadPrivate::removeObjectWithPendingBindingStatusChange(QObject *obj) { - if (m_statusOrPendingObjects.bindingStatus()) + if (data->m_statusOrPendingObjects.bindingStatus()) return; QMutexLocker lock(&mutex); - m_statusOrPendingObjects.removeObject(obj); + data->m_statusOrPendingObjects.removeObject(obj); } -- cgit v1.2.3