diff --git a/src/core/AsyncTask.h b/src/core/AsyncTask.h index f74d7c73..b113134d 100644 --- a/src/core/AsyncTask.h +++ b/src/core/AsyncTask.h @@ -58,6 +58,28 @@ namespace AsyncTask return waitForFuture(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 + void runThenCallback(FunctionObject task, QObject* context, FunctionObject2 callback) + { + typedef QFutureWatcher::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 diff --git a/src/core/FileWatcher.cpp b/src/core/FileWatcher.cpp index 2d37734a..430e6027 100644 --- a/src/core/FileWatcher.cpp +++ b/src/core/FileWatcher.cpp @@ -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()