Skip to content

Commit 89a95dd

Browse files
committed
--performance-valueflow-max-if-count: review comments
1 parent 39f94f3 commit 89a95dd

File tree

5 files changed

+83
-16
lines changed

5 files changed

+83
-16
lines changed

Diff for: cli/cmdlineparser.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -1220,8 +1220,7 @@ void CmdLineParser::printHelp()
12201220
" the number of possible control flow paths through that\n"
12211221
" function explodes and that can lead to very long analysis\n"
12221222
" time. Valueflow is limited in functions that have more\n"
1223-
" than <limit> conditional scopes. The default limit is\n"
1224-
" 100, which few functions will reach.\n"
1223+
" than <limit> conditional scopes.\n"
12251224
" --platform=<type>, --platform=<file>\n"
12261225
" Specifies platform specific types and sizes. The\n"
12271226
" available builtin platforms are:\n"

Diff for: lib/valueflow.cpp

+24-13
Original file line numberDiff line numberDiff line change
@@ -8501,10 +8501,17 @@ static void valueFlowContainerSetTokValue(TokenList* tokenlist, const Settings*
85018501
}
85028502
}
85038503

8504+
static const Scope* getFunctionScope(const Scope* scope) {
8505+
while (scope && scope->type != Scope::ScopeType::eFunction)
8506+
scope = scope->nestedIn;
8507+
return scope;
8508+
}
8509+
85048510
static void valueFlowContainerSize(TokenList* tokenlist,
85058511
SymbolDatabase* symboldatabase,
85068512
ErrorLogger* /*errorLogger*/,
8507-
const Settings* settings)
8513+
const Settings* settings,
8514+
const std::set<const Scope*>& skippedFunctions)
85088515
{
85098516
// declaration
85108517
for (const Variable *var : symboldatabase->variableList()) {
@@ -8516,6 +8523,8 @@ static void valueFlowContainerSize(TokenList* tokenlist,
85168523
continue;
85178524
if (!astIsContainer(var->nameToken()))
85188525
continue;
8526+
if (skippedFunctions.count(getFunctionScope(var->scope())))
8527+
continue;
85198528

85208529
bool known = true;
85218530
int size = 0;
@@ -9077,7 +9086,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
90779086
const std::uint64_t stopTime = getValueFlowStopTime(settings);
90789087

90799088
std::set<const Scope*> skippedFunctions;
9080-
if (settings->performanceValueFlowMaxIfCount < 1000) {
9089+
if (settings->performanceValueFlowMaxIfCount > 0) {
90819090
for (const Scope* functionScope: symboldatabase->functionScopes) {
90829091
int countIfScopes = 0;
90839092
std::vector<const Scope*> scopes{functionScope};
@@ -9093,15 +9102,17 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
90939102
if (countIfScopes > settings->performanceValueFlowMaxIfCount) {
90949103
skippedFunctions.emplace(functionScope);
90959104

9096-
const std::string& functionName = functionScope->className;
9097-
const std::list<ErrorMessage::FileLocation> callstack(1, ErrorMessage::FileLocation(functionScope->bodyStart, tokenlist));
9098-
const ErrorMessage errmsg(callstack, tokenlist->getSourceFilePath(), Severity::information,
9099-
"ValueFlow analysis is limited in " + functionName + " because if-count in function " +
9100-
std::to_string(countIfScopes) + " exceeds limit " +
9101-
std::to_string(settings->performanceValueFlowMaxIfCount) + ". The limit can be adjusted with "
9102-
"--performance-valueflow-max-if-count. Increasing the if-count limit will likely increase the "
9103-
"analysis time.", "performanceValueflowMaxIfCountExceeded", Certainty::normal);
9104-
errorLogger->reportErr(errmsg);
9105+
if (settings->severity.isEnabled(Severity::information)) {
9106+
const std::string& functionName = functionScope->className;
9107+
const std::list<ErrorMessage::FileLocation> callstack(1, ErrorMessage::FileLocation(functionScope->bodyStart, tokenlist));
9108+
const ErrorMessage errmsg(callstack, tokenlist->getSourceFilePath(), Severity::information,
9109+
"ValueFlow analysis is limited in " + functionName + " because if-count in function " +
9110+
std::to_string(countIfScopes) + " exceeds limit " +
9111+
std::to_string(settings->performanceValueFlowMaxIfCount) + ". The limit can be adjusted with "
9112+
"--performance-valueflow-max-if-count. Increasing the if-count limit will likely increase the "
9113+
"analysis time.", "performanceValueflowMaxIfCountExceeded", Certainty::normal);
9114+
errorLogger->reportErr(errmsg);
9115+
}
91059116
}
91069117
}
91079118
}
@@ -9159,8 +9170,8 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
91599170
valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
91609171
if (std::time(nullptr) < stopTime)
91619172
valueFlowIteratorInfer(tokenlist, settings);
9162-
if (std::time(nullptr) < stopTime && skippedFunctions.empty())
9163-
valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings);
9173+
if (std::time(nullptr) < stopTime)
9174+
valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
91649175
if (std::time(nullptr) < stopTime)
91659176
valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
91669177
}

Diff for: man/manual.md

+28
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,34 @@ Example usage:
957957
./cppcheck gui/test.cpp --xml 2> err.xml
958958
htmlreport/cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=.
959959

960+
# Performance - Limit analysis
961+
962+
## Limit preprocessor configurations
963+
964+
For performance reasons it might be a good idea to limit preprocessor configurations to check.
965+
966+
## Limit ValueFlow: max if count
967+
968+
The command line option `--performance-valueflow-max-if-count` adjusts the max count for number of if in a function.
969+
970+
When that limit is exceeded there is a limitation of data flow in that function. It is not drastic:
971+
* Analysis of other functions are not affected.
972+
* It's only for some specific data flow analysis, we have data flow analysis that is always executed.
973+
* All checks are always executed. There can still be plenty of warnings in the limited function.
974+
975+
There is data flow analysis that slows down exponentially when number of if increase. And the limit is intended to avoid that
976+
analysis time explodes.
977+
978+
## GUI options
979+
980+
In the GUI there are various options to limit analysis.
981+
982+
In the GUI:
983+
* Open the project dialog.
984+
* In the "Analysis" tab there are several options.
985+
986+
If you want to use these limitations on the command line also you can import the GUI project file with --project.
987+
960988
# Cppcheck Premium
961989

962990
## Bug hunting

Diff for: releasenotes.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ release notes for cppcheck-2.11
1212
- `constVariable`
1313
- `constVariableReference`
1414
- `constVariablePointer`
15-
15+
- Limit valueflow analysis in function if the "if" count is high. By default max limit is 100. Limit can be tweaked with --performance-valueflow-max-if-count

Diff for: test/testvalueflow.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ class TestValueFlow : public TestFixture {
164164
TEST_CASE(valueFlowImpossibleMinMax);
165165
TEST_CASE(valueFlowImpossibleUnknownConstant);
166166
TEST_CASE(valueFlowContainerEqual);
167+
168+
TEST_CASE(performanceIfCount);
167169
}
168170

169171
static bool isNotTokValue(const ValueFlow::Value &val) {
@@ -7942,6 +7944,33 @@ class TestValueFlow : public TestFixture {
79427944
ASSERT_EQUALS(false, testValueOfX(code, 5U, 1));
79437945
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
79447946
}
7947+
7948+
void performanceIfCount() {
7949+
Settings s(settings);
7950+
s.performanceValueFlowMaxIfCount = 1;
7951+
7952+
const char *code;
7953+
7954+
code = "int f() {\n"
7955+
" if (x>0){}\n"
7956+
" if (y>0){}\n"
7957+
" int a = 14;\n"
7958+
" return a+1;\n"
7959+
"}\n";
7960+
ASSERT_EQUALS(0U, tokenValues(code, "+", &s).size());
7961+
ASSERT_EQUALS(1U, tokenValues(code, "+").size());
7962+
7963+
// Do not skip all functions
7964+
code = "void g(int i) {\n"
7965+
" if (i == 1) {}\n"
7966+
" if (i == 2) {}\n"
7967+
"}\n"
7968+
"int f() {\n"
7969+
" std::vector<int> v;\n"
7970+
" return v.front();\n"
7971+
"}\n";
7972+
ASSERT_EQUALS(1U, tokenValues(code, "v .", &s).size());
7973+
}
79457974
};
79467975

79477976
REGISTER_TEST(TestValueFlow)

0 commit comments

Comments
 (0)