summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArno Rehn <[email protected]>2023-06-15 17:12:02 +0200
committerArno Rehn <[email protected]>2023-06-21 07:40:40 +0000
commitde8eafc5a0787de215dd55f8a5fdc93ef52fabcb (patch)
tree4739529c739825c662bb40810d241541a750d146
parent3d806a4f66070e23307f62cff8cfcea12dd5113e (diff)
QPromise: Propagate cancellation through failure handlers
Previously, failure handlers did not propagate cancellation. This would lead to crashes when a QPromise was cancelled without having generated any result. Subsequent continuations would be invoked and try to access the result (which was nonexistent) and then crash. This patch propagates cancellation through failure handlers to prevent subsequent continuations from being called in the first place. Fixes: QTBUG-114606 Change-Id: I23b28a8e70a76e1ba6416be4440360c6dbaef2a3 Reviewed-by: Ivan Solovev <[email protected]> (cherry picked from commit 855c4484693015cb6498f2183d95de1377d49898) Reviewed-by: Volker Hilsheimer <[email protected]>
-rw-r--r--src/corelib/thread/qfuture_impl.h2
-rw-r--r--tests/auto/corelib/thread/qpromise/tst_qpromise.cpp33
2 files changed, 35 insertions, 0 deletions
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 58169bd05bf..bcf29eb37e4 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -721,6 +721,8 @@ void FailureHandler<Function, ResultType>::run()
} else {
handleException<ArgType>();
}
+ } else if (parentFuture.d.isChainCanceled()) {
+ promise.future().cancel();
} else {
QtPrivate::fulfillPromise(promise, parentFuture);
}
diff --git a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
index 4dd4219e00a..df410629fa4 100644
--- a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
+++ b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
@@ -41,6 +41,7 @@ private slots:
void cancelWhenReassigned();
void cancelWhenDestroyedWithoutStarting();
void cancelWhenDestroyedRunsContinuations();
+ void cancelWhenDestroyedWithFailureHandler(); // QTBUG-114606
void continuationsRunWhenFinished();
void finishWhenSwapped();
void cancelWhenMoved();
@@ -544,6 +545,38 @@ void tst_QPromise::cancelWhenDestroyedRunsContinuations()
}
template <typename T>
+static inline void testCancelWhenDestroyedWithFailureHandler()
+{
+ QFuture<T> future;
+ bool onFailedCalled = false;
+ bool thenCalled = false;
+ {
+ QPromise<T> promise;
+ future = promise.future();
+ future
+ .onFailed([&] () {
+ onFailedCalled = true;
+ if constexpr (!std::is_same_v<void, T>)
+ return T{};
+ })
+ .then([&] (auto&&) {
+ thenCalled = true;
+ });
+ }
+ QVERIFY(future.isFinished());
+ QVERIFY(!onFailedCalled);
+ QVERIFY(!thenCalled);
+}
+
+void tst_QPromise::cancelWhenDestroyedWithFailureHandler()
+{
+ testCancelWhenDestroyedWithFailureHandler<void>();
+ testCancelWhenDestroyedWithFailureHandler<int>();
+ testCancelWhenDestroyedWithFailureHandler<CopyOnlyType>();
+ testCancelWhenDestroyedWithFailureHandler<MoveOnlyType>();
+}
+
+template <typename T>
static inline void testContinuationsRunWhenFinished()
{
QPromise<T> promise;