diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index bc99f4e91..ca171fbbd 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -219,6 +219,10 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) else if (std::strcmp(argv[i], "--bug-hunting") == 0) mSettings->bugHunting = true; + // TODO: Rename or move this parameter? + else if (std::strncmp(argv[i], "--bug-hunting-check-function-max-time=", 38) == 0) + mSettings->bugHuntingCheckFunctionMaxTime = std::atoi(argv[i] + 38); + // Check configuration else if (std::strcmp(argv[i], "--check-config") == 0) mSettings->checkConfiguration = true; diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp index 7982bfd9c..9cc525879 100644 --- a/lib/exprengine.cpp +++ b/lib/exprengine.cpp @@ -2428,6 +2428,10 @@ static std::string execute(const Token *start, const Token *end, Data &data) }; Recursion updateRecursion(&data.recursion, data.recursion); + const std::time_t stopTime = (data.settings->bugHuntingCheckFunctionMaxTime > 0) ? + (data.startTime + data.settings->bugHuntingCheckFunctionMaxTime) : + ~0ULL; + for (const Token *tok = start; tok != end; tok = tok->next()) { if (Token::Match(tok, "[;{}]")) { data.trackProgramState(tok); @@ -2438,6 +2442,8 @@ static std::string execute(const Token *start, const Token *end, Data &data) if (Token::Match(prev, "[;{}] return|throw")) return data.str(); } + if (std::time(nullptr) > stopTime) + return ""; } if (Token::simpleMatch(tok, "__CPPCHECK_BAILOUT__ ;")) @@ -2850,6 +2856,10 @@ void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorL data.contractConstraints(function, executeExpression1); + const std::time_t stopTime = (data.settings->bugHuntingCheckFunctionMaxTime > 0) ? + (data.startTime + data.settings->bugHuntingCheckFunctionMaxTime) : + ~0ULL; + try { execute(functionScope->bodyStart, functionScope->bodyEnd, data); } catch (const ExprEngineException &e) { @@ -2858,6 +2868,8 @@ void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorL trackExecution.setAbortLine(e.tok->linenr()); auto bailoutValue = std::make_shared(); for (const Token *tok = e.tok; tok != functionScope->bodyEnd; tok = tok->next()) { + if (std::time(nullptr) >= stopTime) + break; if (Token::Match(tok, "return|throw|while|if|for (")) { tok = tok->next(); continue; diff --git a/lib/settings.cpp b/lib/settings.cpp index f59e05aee..815eea9d9 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -31,6 +31,7 @@ const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables"; Settings::Settings() : mEnabled(0), bugHunting(false), + bugHuntingCheckFunctionMaxTime(0), checkAllConfigurations(true), checkConfiguration(false), checkHeaders(true), diff --git a/lib/settings.h b/lib/settings.h index 099ade030..ba0d8031e 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -83,6 +83,10 @@ public: /** @brief Bug hunting */ bool bugHunting; + /** @brief Max time for bug hunting analysis in seconds, after + * timeout the analysis will just stop. */ + int bugHuntingCheckFunctionMaxTime; + /** Filename for bug hunting report */ std::string bugHuntingReport; diff --git a/test/bug-hunting/itc.py b/test/bug-hunting/itc.py index bd77e1780..55f312372 100644 --- a/test/bug-hunting/itc.py +++ b/test/bug-hunting/itc.py @@ -44,6 +44,7 @@ def get_error_lines(filename): def check(filename): cmd = [CPPCHECK_PATH, '--bug-hunting', + '--bug-hunting-check-function-max-time=10' '--platform=unix64', filename] if RUN_CLANG: