From 9923a901008654794a84f357a69e60b77cc86aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 7 Apr 2021 14:27:21 +0200 Subject: [PATCH] QtFuture::connect: disconnect signals first During reportFinished we may call a continuation which might end up triggering one of the signals. Change-Id: I19546fcca12be71cd536e4287eb5eddd9d236830 Reviewed-by: Sona Kurazyan Reviewed-by: Fabian Kosmale (cherry picked from commit bb85831e4de5e2c4951a0c40003ccf36f57cbd93) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/thread/qfuture_impl.h | 14 +++++++------- .../corelib/thread/qfuture/tst_qfuture.cpp | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h index 8e7ba0c4b59..e455a74793d 100644 --- a/src/corelib/thread/qfuture_impl.h +++ b/src/corelib/thread/qfuture_impl.h @@ -807,34 +807,34 @@ static QFuture> connect(Sender *sender, Signal signal) if constexpr (std::is_void_v) { connections->first = QObject::connect(sender, signal, sender, [promise, connections]() mutable { - promise.reportFinished(); QObject::disconnect(connections->first); QObject::disconnect(connections->second); + promise.reportFinished(); }); } else if constexpr (QtPrivate::isTupleV) { connections->first = QObject::connect(sender, signal, sender, [promise, connections](auto... values) mutable { - promise.reportResult(std::make_tuple(values...)); - promise.reportFinished(); QObject::disconnect(connections->first); QObject::disconnect(connections->second); + promise.reportResult(std::make_tuple(values...)); + promise.reportFinished(); }); } else { connections->first = QObject::connect(sender, signal, sender, [promise, connections](ArgsType value) mutable { - promise.reportResult(value); - promise.reportFinished(); QObject::disconnect(connections->first); QObject::disconnect(connections->second); + promise.reportResult(value); + promise.reportFinished(); }); } connections->second = QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable { - promise.reportCanceled(); - promise.reportFinished(); QObject::disconnect(connections->first); QObject::disconnect(connections->second); + promise.reportCanceled(); + promise.reportFinished(); }); return promise.future(); diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index 71cfbd054b7..5f6267ec7d6 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -3228,6 +3228,25 @@ void tst_QFuture::signalConnect() QVERIFY(future.isCanceled()); QVERIFY(!future.isValid()); } + + // Signal emitted, causing Sender to be destroyed + { + SenderObject *sender = new SenderObject(); + + auto future = QtFuture::connect(sender, &SenderObject::intArgSignal); + future.then([sender](int) { + // Scenario: Sender no longer needed, so it's deleted + delete sender; + }); + + QSignalSpy spy(sender, &SenderObject::destroyed); + emit sender->intArgSignal(5); + spy.wait(); + + QVERIFY(future.isFinished()); + QVERIFY(!future.isCanceled()); + QVERIFY(future.isValid()); + } } void tst_QFuture::waitForFinished()