Introduce AsyncTask::runThenCallback

* Fixes #5295
* Introduce a callback approach to AsyncTask instead of entering multiple QEventLoop in the stack. This has additional benefits including not returning to the original stack location and potentially operating on deleted objects (use after free).
This commit is contained in:
Jonathan White 2020-09-27 10:29:46 -04:00
parent fd8d81f517
commit 443b9e4d37
2 changed files with 31 additions and 6 deletions

View File

@ -58,6 +58,28 @@ namespace AsyncTask
return waitForFuture<FunctionObject>(QtConcurrent::run(task));
}
/**
* Run a given task then call the defined callback. Prevents event loop blocking and
* ensures the validity of the follow-on task through the context. If the context is
* deleted, the callback will not be processed preventing use after free errors.
*
* @param task std::function object to run
* @param context QObject responsible for calling this function
* @param callback std::function object to run after the task completess
*/
template <typename FunctionObject, typename FunctionObject2>
void runThenCallback(FunctionObject task, QObject* context, FunctionObject2 callback)
{
typedef QFutureWatcher<typename std::result_of<FunctionObject()>::type> FutureWatcher;
auto future = QtConcurrent::run(task);
auto watcher = new FutureWatcher(context);
QObject::connect(watcher, &QFutureWatcherBase::finished, context, [=]() {
watcher->deleteLater();
callback(future.result());
});
watcher->setFuture(future);
}
}; // namespace AsyncTask
#endif // KEEPASSXC_ASYNCTASK_HPP

View File

@ -118,13 +118,16 @@ void FileWatcher::checkFileChanged()
// Prevent reentrance
m_ignoreFileChange = true;
auto checksum = AsyncTask::runAndWaitForFuture([this]() -> QByteArray { return calculateChecksum(); });
if (checksum != m_fileChecksum) {
m_fileChecksum = checksum;
m_fileChangeDelayTimer.start(0);
}
AsyncTask::runThenCallback([=] { return calculateChecksum(); },
this,
[=](QByteArray checksum) {
if (checksum != m_fileChecksum) {
m_fileChecksum = checksum;
m_fileChangeDelayTimer.start(0);
}
m_ignoreFileChange = false;
m_ignoreFileChange = false;
});
}
QByteArray FileWatcher::calculateChecksum()