diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-02-09 16:12:15 +0100 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-02-15 15:12:12 +0100 |
commit | b34bea5e96370986ea5dfc499fc2ec6366fda627 (patch) | |
tree | e7be05a28c796a93708c7c4941452454ca100b0b /tests/auto/corelib/thread | |
parent | ec8e6ed20034a5ea7d32bdc62b3b9dc91ce68d36 (diff) |
QFuture: fix continuation cleanup
Not clearing the continuationData could lead to use-after-free when
there is an attempt to cancel an already finished future, which belongs
to an already-destroyed promise.
This patch fixes it be explicitly resetting continuationData to nullptr
in the clearContinuation() method, which is called from the QPromise
destructor.
Task-number: QTBUG-103514
Pick-to: 6.5 6.4 6.2
Change-Id: I6418b3f5ad04f2fdc13a196ae208009eaa5de367
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'tests/auto/corelib/thread')
-rw-r--r-- | tests/auto/corelib/thread/qfuture/tst_qfuture.cpp | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index 9234204bdc..deba56d3b1 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -221,6 +221,7 @@ private slots: void whenAnyDifferentTypesWithFailed(); void continuationsDontLeak(); + void cancelAfterFinishWithContinuations(); void unwrap(); @@ -4721,6 +4722,31 @@ void tst_QFuture::continuationsDontLeak() QCOMPARE(InstanceCounter::count, 0); } +// This test checks that we do not get use-after-free +void tst_QFuture::cancelAfterFinishWithContinuations() +{ + QFuture<void> future; + bool continuationIsRun = false; + bool cancelCalled = false; + { + QPromise<void> promise; + future = promise.future(); + + future.then([&continuationIsRun]() { + continuationIsRun = true; + }).onCanceled([&cancelCalled]() { + cancelCalled = true; + }); + + promise.start(); + promise.finish(); + } + + QVERIFY(continuationIsRun); + future.cancel(); + QVERIFY(!cancelCalled); +} + void tst_QFuture::unwrap() { // The nested future succeeds |