From c08842daea9a45eeb79be6e422e751f67290eb02 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Tue, 15 Mar 2022 00:07:37 +0100 Subject: [PATCH] QFuture: fix QtFuture::connect corner-cases Connecting to nullptr, or connecting to a non-signal PMF, would result in a QFuture which would never finish. Catch these cases and handle them. Windows+MSVC for some reason fails the test. I can't entirely understand why, so I've marked it as XFAIL, with QTBUG-101761 to track it. Change-Id: I314980e7e9b7156d8cddd3b33d5cbf1d0bcd6116 Reviewed-by: Thiago Macieira Reviewed-by: Andrei Golubev (cherry picked from commit 5089db0303f4ee0ca0d7c6814e06beff119d8500) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/thread/qfuture_impl.h | 11 +++++++ .../corelib/thread/qfuture/tst_qfuture.cpp | 30 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h index 57c4fb399c1..06b618873d2 100644 --- a/src/corelib/thread/qfuture_impl.h +++ b/src/corelib/thread/qfuture_impl.h @@ -832,6 +832,11 @@ static QFuture> connect(Sender *sender, Signal signal) using ArgsType = ArgsType; QFutureInterface promise; promise.reportStarted(); + if (!sender) { + promise.reportCanceled(); + promise.reportFinished(); + return promise.future(); + } using Connections = std::pair; auto connections = std::make_shared(); @@ -862,6 +867,12 @@ static QFuture> connect(Sender *sender, Signal signal) }); } + if (!connections->first) { + promise.reportCanceled(); + promise.reportFinished(); + return promise.future(); + } + connections->second = QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable { QObject::disconnect(connections->first); diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index 9742df36ea5..7b508b8a22b 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -3667,6 +3667,36 @@ void tst_QFuture::signalConnect() QVERIFY(!future.isCanceled()); QVERIFY(future.isValid()); } + + // Connect to nullptr + { + SenderObject *sender = nullptr; + auto future = QtFuture::connect(sender, &SenderObject::intArgSignal); + QVERIFY(future.isFinished()); + QVERIFY(future.isCanceled()); + QVERIFY(!future.isValid()); + } + + // Connect to non-signal + { + SenderObject sender; + +#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) +#define EXPECT_FUTURE_CONNECT_FAIL() QEXPECT_FAIL("", "QTBUG-101761, test fails on Windows/MSVC", Continue) +#else + QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in SenderObject"); +#define EXPECT_FUTURE_CONNECT_FAIL() +#endif + + auto future = QtFuture::connect(&sender, &SenderObject::emitNoArg); + EXPECT_FUTURE_CONNECT_FAIL(); + QVERIFY(future.isFinished()); + EXPECT_FUTURE_CONNECT_FAIL(); + QVERIFY(future.isCanceled()); + EXPECT_FUTURE_CONNECT_FAIL(); + QVERIFY(!future.isValid()); +#undef EXPECT_FUTURE_CONNECT_FAIL + } } void tst_QFuture::waitForFinished()