From 917214c4992604bac494e82e56a2bed0c42892fc Mon Sep 17 00:00:00 2001 From: Mat Sutcliffe Date: Sat, 27 Oct 2018 22:31:09 +0100 Subject: [PATCH] Ref T414 Use a promise/future pair in CWorker::thenWithResult to avoid accessing the worker after it was potentially destroyed. --- src/blackmisc/worker.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/blackmisc/worker.h b/src/blackmisc/worker.h index b0cf820b9..3d9c31c64 100644 --- a/src/blackmisc/worker.h +++ b/src/blackmisc/worker.h @@ -37,6 +37,7 @@ #include #include #include +#include namespace BlackMisc { @@ -244,7 +245,14 @@ namespace BlackMisc void thenWithResult(T *context, F functor) { Q_ASSERT_X(m_result.canConvert(), Q_FUNC_INFO, "Type in thenWithResult must match return type of task"); - then(context, [this, context, functor]() { Private::invokeSlot(functor, context, this->resultNoWait()); }); + + // MS 2018-10 It is possible that a queued finished() signal will be delivered after the worker was + // destroyed, so we can't refer to the this pointer inside the contextual then() lambda. + // Therefore we use a promise to extract the result from a non-contextual then(). See T414. + auto promise = std::make_shared>(); + auto future = promise->get_future().share(); + then([this, promise]() { promise->set_value(this->resultNoWait()); }); + then(context, [context, functor, future]() { Private::invokeSlot(functor, context, future.get()); }); } //! Returns the result of the task, waiting for it to finish if necessary.