added command-line option `--valueflow-max-iterations` to control amount of valueflow iterations / also log debug warning when iterations are being exceeded (#4557)

This commit is contained in:
Oliver Stöneberg 2022-12-20 20:51:08 +01:00 committed by GitHub
parent 3c68b9b29f
commit b380fd2589
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 1 deletions

View File

@ -915,6 +915,21 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
} }
} }
else if (std::strncmp(argv[i], "--valueflow-max-iterations=", 27) == 0) {
long tmp;
try {
tmp = std::stol(argv[i] + 27);
} catch (const std::invalid_argument &) {
printError("argument to '--valueflow-max-iteration' is invalid.");
return false;
}
if (tmp < 0) {
printError("argument to '--valueflow-max-iteration' needs to be at least 0.");
return false;
}
mSettings->valueFlowMaxIterations = static_cast<std::size_t>(tmp);
}
else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0) else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0)
mSettings->verbose = true; mSettings->verbose = true;

View File

@ -66,6 +66,7 @@ Settings::Settings()
relativePaths(false), relativePaths(false),
reportProgress(false), reportProgress(false),
showtime(SHOWTIME_MODES::SHOWTIME_NONE), showtime(SHOWTIME_MODES::SHOWTIME_NONE),
valueFlowMaxIterations(4),
verbose(false), verbose(false),
xml(false), xml(false),
xml_version(2) xml_version(2)

View File

@ -351,6 +351,9 @@ public:
/** @brief forced includes given by the user */ /** @brief forced includes given by the user */
std::list<std::string> userIncludes; std::list<std::string> userIncludes;
/** @brief the maximum iterations of valueflow (--valueflow-max-iterations=T) */
std::size_t valueFlowMaxIterations;
/** @brief Is --verbose given? */ /** @brief Is --verbose given? */
bool verbose; bool verbose;

View File

@ -8986,7 +8986,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
const std::uint64_t stopTime = getValueFlowStopTime(settings); const std::uint64_t stopTime = getValueFlowStopTime(settings);
std::size_t values = 0; std::size_t values = 0;
std::size_t n = 4; std::size_t n = settings->valueFlowMaxIterations;
while (n > 0 && values != getTotalValues(tokenlist)) { while (n > 0 && values != getTotalValues(tokenlist)) {
values = getTotalValues(tokenlist); values = getTotalValues(tokenlist);
@ -9048,6 +9048,18 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
n--; n--;
} }
if (settings->debugwarnings) {
if (n == 0 && values != getTotalValues(tokenlist)) {
ErrorMessage errmsg({},
emptyString,
Severity::debug,
"ValueFlow maximum iterations exceeded",
"valueFlowMaxIterations",
Certainty::normal);
errorLogger->reportErr(errmsg);
}
}
if (std::time(nullptr) < stopTime) if (std::time(nullptr) < stopTime)
valueFlowDynamicBufferSize(tokenlist, symboldatabase, settings); valueFlowDynamicBufferSize(tokenlist, symboldatabase, settings);

View File

@ -153,6 +153,11 @@ private:
TEST_CASE(clang); TEST_CASE(clang);
TEST_CASE(clang2); TEST_CASE(clang2);
TEST_CASE(clangInvalid); TEST_CASE(clangInvalid);
TEST_CASE(valueFlowMaxIterations);
TEST_CASE(valueFlowMaxIterations2);
TEST_CASE(valueFlowMaxIterationsInvalid);
TEST_CASE(valueFlowMaxIterationsInvalid2);
TEST_CASE(valueFlowMaxIterationsInvalid3);
// TODO // TODO
// Disabling these tests since they use relative paths to the // Disabling these tests since they use relative paths to the
@ -1260,6 +1265,45 @@ private:
ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--clang-foo\".\n", GET_REDIRECT_OUTPUT); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--clang-foo\".\n", GET_REDIRECT_OUTPUT);
} }
void valueFlowMaxIterations() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=0"};
settings.valueFlowMaxIterations = -1;
ASSERT(defParser.parseFromArgs(2, argv));
ASSERT_EQUALS(0, settings.valueFlowMaxIterations);
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
}
void valueFlowMaxIterations2() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=11"};
settings.valueFlowMaxIterations = -1;
ASSERT(defParser.parseFromArgs(2, argv));
ASSERT_EQUALS(11, settings.valueFlowMaxIterations);
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
}
void valueFlowMaxIterationsInvalid() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--valueflow-max-iterations"};
ASSERT(!defParser.parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--valueflow-max-iterations\".\n", GET_REDIRECT_OUTPUT);
}
void valueFlowMaxIterationsInvalid2() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=seven"};
ASSERT(!defParser.parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iteration' is invalid.\n", GET_REDIRECT_OUTPUT);
}
void valueFlowMaxIterationsInvalid3() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=-1"};
ASSERT(!defParser.parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iteration' needs to be at least 0.\n", GET_REDIRECT_OUTPUT);
}
/* /*
void ignorepaths1() { void ignorepaths1() {
REDIRECT; REDIRECT;