diff options
| author | Mason Reed <35282038+emesare@users.noreply.github.com> | 2026-04-23 14:16:33 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-23 14:16:33 -0700 |
| commit | ca64b858f6c4ae95c1ea5b0aa6c2fc32292cf8c7 (patch) | |
| tree | 89d328691f97bd5420e40a7016c3865fcdc5b20f /plugins/warp | |
| parent | aa8dab21d44b4e0dd863f0867c7e735cfb878a4d (diff) | |
[WARP] Fix misc UI thread safety issues (#8112)
Diffstat (limited to 'plugins/warp')
| -rw-r--r-- | plugins/warp/ui/matches.cpp | 35 | ||||
| -rw-r--r-- | plugins/warp/ui/shared/fetcher.cpp | 1 |
2 files changed, 27 insertions, 9 deletions
diff --git a/plugins/warp/ui/matches.cpp b/plugins/warp/ui/matches.cpp index 918312fd..2af17383 100644 --- a/plugins/warp/ui/matches.cpp +++ b/plugins/warp/ui/matches.cpp @@ -8,6 +8,7 @@ #include <thread> #include <QGridLayout> #include <QHeaderView> +#include <QtConcurrent/QtConcurrent> WarpCurrentFunctionWidget::WarpCurrentFunctionWidget(QWidget* parent) : QWidget(parent) { @@ -151,22 +152,38 @@ void WarpCurrentFunctionWidget::SetCurrentFunction(FunctionRef current) m_current = current; m_infoWidget->SetAnalysisFunction(m_current); - // If we have a fetcher we should also let it know to try and fetch the possible functions from the containers. + // If we have a fetcher, we should also let it know to try and fetch the possible functions from the containers. if (current && m_fetcher) { m_fetcher->AddPendingFunction(current); - - // TODO: Automatically fetch the function, I need to figure out how to make this debounce correctly so that all - // requests are processed in line. if (!m_fetcher->m_requestInProgress.exchange(true)) { - BinaryNinja::WorkerPriorityEnqueue([this]() { - QMetaObject::invokeMethod(this, [this] { m_spinner->show(); }, Qt::QueuedConnection); + // Don't block the UI thread when fetching, also unlike other cases where we reach for QtConcurrent::run we + // do not use a watcher to tie the future to the widget's lifetime, this is because network requests can + // take a long time, and we want to avoid blocking the UI thread in the widget destructor. Instead of + // ensuring the widget is alive, we just use a weak pointer that can tell us when it (self) has been + // destructed. + auto future = QtConcurrent::run([self = QPointer(this), current, fetcher = m_fetcher]() { + if (!self) + return; + QMetaObject::invokeMethod( + self, + [self] { + if (self) + self->m_spinner->show(); + }, + Qt::QueuedConnection); BinaryNinja::Ref bgTask = new BinaryNinja::BackgroundTask("Fetching WARP Functions...", true); - const auto allowedTags = GetAllowedTagsFromView(m_current->GetView()); - m_fetcher->FetchPendingFunctions(allowedTags); + const auto allowedTags = GetAllowedTagsFromView(current->GetView()); + fetcher->FetchPendingFunctions(allowedTags); bgTask->Finish(); - QMetaObject::invokeMethod(this, [this] { m_spinner->hide(); }, Qt::QueuedConnection); + QMetaObject::invokeMethod( + self, + [self] { + if (self) + self->m_spinner->hide(); + }, + Qt::QueuedConnection); }); } } diff --git a/plugins/warp/ui/shared/fetcher.cpp b/plugins/warp/ui/shared/fetcher.cpp index f5aa626a..daa3fece 100644 --- a/plugins/warp/ui/shared/fetcher.cpp +++ b/plugins/warp/ui/shared/fetcher.cpp @@ -113,6 +113,7 @@ void WarpFetcher::FetchPendingFunctions(const std::vector<Warp::SourceTag>& allo void WarpFetcher::ClearProcessed() { + std::lock_guard<std::mutex> lock(m_requestMutex); m_logger->LogInfoF("Clearing {} processed functions from cache...", m_processedGuids.size()); m_processedGuids.clear(); } |
