QFuture: Fix for heap-use-after-free on qfutureinterface watch

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 <a.rehn@menlosystems.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Philip Schuchardt 2024-06-01 12:55:29 -05:00 committed by Arno Rehn
parent 84a618809a
commit 2bc82f6a11

View File

@ -84,7 +84,13 @@ void QtPrivate::watchContinuationImpl(const QObject *context, QSlotObjectBase *s
void *args[] = { nullptr }; // for `void` return value void *args[] = { nullptr }; // for `void` return value
slot->call(nullptr, args); 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); QObject::connect(context, &QObject::destroyed, watcher, destroyWatcher);
fi.setContinuation([watcherMutex, watcher = QPointer(watcher)] fi.setContinuation([watcherMutex, watcher = QPointer(watcher)]