From cd70d10dce8993d9923619aa4582b5c84a46b12e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 13:02:25 +0200 Subject: [PATCH] SilverSearcher: Don't crash on giant output from ag Make cancel and continue button working. Make pausing above 200000 hits working. Fixes: QTCREATORBUG-29130 Change-Id: I55429ae1b4d80dacfcd7e8366133657d0c44a0d6 Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- .../findinfilessilversearcher.cpp | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index b7e26d071b1..7d9e5f1e141 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -114,10 +114,31 @@ static void runSilverSeacher(QPromise &promise, process.setCommand({"ag", arguments}); ParserState parserState; const std::optional regExp = regExpFromParameters(parameters); - process.setStdOutCallback([&promise, &parserState, regExp](const QString &output) { - SilverSearcher::parse(promise, output, &parserState, regExp); + QStringList outputBuffer; + // The states transition exactly in this order: + enum State { BelowLimit, AboveLimit, Paused, Resumed }; + State state = BelowLimit; + process.setStdOutCallback([&process, &loop, &promise, &state, &outputBuffer, &parserState, + regExp](const QString &output) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + return; + } + // The SearchResultWidget is going to pause the search anyway, so start buffering + // the output. + if (state == AboveLimit || state == Paused) { + outputBuffer.append(output); + } else { + SilverSearcher::parse(promise, output, &parserState, regExp); + if (state == BelowLimit && parserState.m_reportedResultsCount > 200000) + state = AboveLimit; + } + }); + QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] { + if (state == BelowLimit || state == Resumed || promise.isCanceled()) + loop.quit(); }); - QObject::connect(&process, &Process::done, &loop, &QEventLoop::quit); process.start(); if (process.state() == QProcess::NotRunning) @@ -125,7 +146,23 @@ static void runSilverSeacher(QPromise &promise, QFutureWatcher watcher; QFuture future(promise.future()); - QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, &QEventLoop::quit); + QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] { + process.close(); + loop.quit(); + }); + QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; }); + QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop, + [&process, &loop, &promise, &state, &outputBuffer, &parserState, regExp] { + state = Resumed; + for (const QString &output : outputBuffer) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + } + SilverSearcher::parse(promise, output, &parserState, regExp); + } + outputBuffer.clear(); + }); watcher.setFuture(future); loop.exec(QEventLoop::ExcludeUserInputEvents); }