From 2bc82f6a1126025affd6e891efc386c08d5fa013 Mon Sep 17 00:00:00 2001 From: Philip Schuchardt Date: Sat, 1 Jun 2024 12:55:29 -0500 Subject: [PATCH] QFuture: Fix for heap-use-after-free on qfutureinterface watch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace deleteLater with destroyWatcher. If the continuation is called from a separate thread, emit watcher->run() can't detect thatthe watcher has been deleted in the separate thread, causing a race condition and potential heap-use-after-free issue inside QObject::doActivate. destroyWatcher forces the deletion of the watcher to occur after emit watcher->run() completes and prevents the race condition. Fixes: QTBUG-126013 Fixes: QTBUG-127880 Pick-to: 6.8 6.7 Change-Id: Id5f80ad0ec3fbd2d9c1e0d134aecd6b08ba2c79c Reviewed-by: Arno Rehn Reviewed-by: MÃ¥rten Nordheim --- src/corelib/thread/qfutureinterface.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index f83306af00c..b967f4e6290 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -84,7 +84,13 @@ void QtPrivate::watchContinuationImpl(const QObject *context, QSlotObjectBase *s void *args[] = { nullptr }; // for `void` return value slot->call(nullptr, args); }); - QObject::connect(watcher, &QObjectContinuationWrapper::run, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QObjectContinuationWrapper::run, watcher, destroyWatcher); + + // We need to connect to destroyWatcher here, instead of delete or deleteLater(). + // If the continuation is called from a separate thread, emit watcher->run() can't detect that + // the watcher has been deleted in the separate thread, causing a race condition and potential + // heap-use-after-free issue inside QObject::doActivate. destroyWatcher forces the deletion of + // the watcher to occur after emit watcher->run() completes and prevents the race condition. QObject::connect(context, &QObject::destroyed, watcher, destroyWatcher); fi.setContinuation([watcherMutex, watcher = QPointer(watcher)]