Skip to content

Commit 6751782

Browse files
author
Your Name
committed
Add a maxForwardConditionForks setting
1 parent 72f3b7d commit 6751782

4 files changed

Lines changed: 83 additions & 4 deletions

File tree

lib/forwardanalyzer.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ namespace {
6161
int branchCount = 0;
6262
// Nested condition-fork depth on this lineage (copied by fork()); bounds the fan-out.
6363
int forkDepth = 0;
64+
// Total forks of the traversal (shared via the fork() copy); backstop past the depth bound.
65+
std::shared_ptr<int> forkBudget = std::make_shared<int>(0);
6466

6567
Progress Break(Analyzer::Terminate t = Analyzer::Terminate::None) {
6668
if ((!analyzeOnly || analyzeTerminate) && t != Analyzer::Terminate::None)
@@ -798,11 +800,15 @@ namespace {
798800
if (thenBranch.hasGoto() || elseBranch.hasGoto()) {
799801
return Break(Analyzer::Terminate::Bail);
800802
}
801-
// Carry the then-fork forward; past the limit only the linear main path
802-
// continues (no branch skipped). Negative == unlimited.
803+
// Carry the then-fork forward, unless a limit is hit - then only the linear main
804+
// path continues (no bail). forkDepth bounds nesting, forkBudget total. <0 = off.
803805
const int forkDepthLimit = settings.vfOptions.maxForwardConditionForkDepth;
804-
if (pThen != Progress::Break && !thenBranch.isEscape() &&
805-
(forkDepthLimit < 0 || forkDepth < forkDepthLimit)) {
806+
const int forkBudgetLimit = settings.vfOptions.maxForwardConditionForks;
807+
const bool depthOk = forkDepthLimit < 0 || forkDepth < forkDepthLimit;
808+
const bool budgetOk = forkBudgetLimit < 0 || !forkBudget || *forkBudget < forkBudgetLimit;
809+
if (pThen != Progress::Break && !thenBranch.isEscape() && depthOk && budgetOk) {
810+
if (forkBudget)
811+
++(*forkBudget);
806812
ft.forkDepth = forkDepth + 1;
807813
ft.updateRange(thenBranch.endBlock, end, depth - 1);
808814
}

lib/settings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ void Settings::setCheckLevel(CheckLevel level)
355355
vfOptions.doConditionExpressionAnalysis = true;
356356
vfOptions.maxForwardBranches = -1;
357357
vfOptions.maxForwardConditionForkDepth = 4;
358+
vfOptions.maxForwardConditionForks = 256;
358359
}
359360
}
360361

lib/settings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
518518
without skipping any branch. 0 disables forking (linear); a negative value means unlimited. */
519519
int maxForwardConditionForkDepth = 4;
520520

521+
/** @brief Maximum total condition-fork continuations in one forward traversal. */
522+
int maxForwardConditionForks = 256;
523+
521524
/** @brief Maximum performed alignof recursion */
522525
int maxAlignOfRecursion = 100;
523526

test/testvalueflow.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8420,6 +8420,75 @@ class TestValueFlow : public TestFixture {
84208420
" static T f[64];\n"
84218421
"};\n";
84228422
(void)valueOfTok(code, "(");
8423+
8424+
// fork explosion on many opaque conditions; bounded by maxForwardConditionForks
8425+
code = "int g(int);\n"
8426+
"bool h(int);\n"
8427+
"void f() {\n"
8428+
" int x = 0;\n"
8429+
" if (h(0)) g(x);\n"
8430+
" if (h(1)) g(x);\n"
8431+
" if (h(2)) g(x);\n"
8432+
" if (h(3)) g(x);\n"
8433+
" if (h(4)) g(x);\n"
8434+
" if (h(5)) g(x);\n"
8435+
" if (h(6)) g(x);\n"
8436+
" if (h(7)) g(x);\n"
8437+
" if (h(8)) g(x);\n"
8438+
" if (h(9)) g(x);\n"
8439+
" if (h(10)) g(x);\n"
8440+
" if (h(11)) g(x);\n"
8441+
" if (h(12)) g(x);\n"
8442+
" if (h(13)) g(x);\n"
8443+
" if (h(14)) g(x);\n"
8444+
" if (h(15)) g(x);\n"
8445+
" if (h(16)) g(x);\n"
8446+
" if (h(17)) g(x);\n"
8447+
" if (h(18)) g(x);\n"
8448+
" if (h(19)) g(x);\n"
8449+
" if (h(20)) g(x);\n"
8450+
" if (h(21)) g(x);\n"
8451+
" if (h(22)) g(x);\n"
8452+
" if (h(23)) g(x);\n"
8453+
" if (h(24)) g(x);\n"
8454+
" if (h(25)) g(x);\n"
8455+
" if (h(26)) g(x);\n"
8456+
" if (h(27)) g(x);\n"
8457+
" if (h(28)) g(x);\n"
8458+
" if (h(29)) g(x);\n"
8459+
" if (h(30)) g(x);\n"
8460+
" if (h(31)) g(x);\n"
8461+
" if (h(32)) g(x);\n"
8462+
" if (h(33)) g(x);\n"
8463+
" if (h(34)) g(x);\n"
8464+
" if (h(35)) g(x);\n"
8465+
" if (h(36)) g(x);\n"
8466+
" if (h(37)) g(x);\n"
8467+
" if (h(38)) g(x);\n"
8468+
" if (h(39)) g(x);\n"
8469+
" if (h(40)) g(x);\n"
8470+
" if (h(41)) g(x);\n"
8471+
" if (h(42)) g(x);\n"
8472+
" if (h(43)) g(x);\n"
8473+
" if (h(44)) g(x);\n"
8474+
" if (h(45)) g(x);\n"
8475+
" if (h(46)) g(x);\n"
8476+
" if (h(47)) g(x);\n"
8477+
" if (h(48)) g(x);\n"
8478+
" if (h(49)) g(x);\n"
8479+
" if (h(50)) g(x);\n"
8480+
" if (h(51)) g(x);\n"
8481+
" if (h(52)) g(x);\n"
8482+
" if (h(53)) g(x);\n"
8483+
" if (h(54)) g(x);\n"
8484+
" if (h(55)) g(x);\n"
8485+
" if (h(56)) g(x);\n"
8486+
" if (h(57)) g(x);\n"
8487+
" if (h(58)) g(x);\n"
8488+
" if (h(59)) g(x);\n"
8489+
" (void)x;\n"
8490+
"}\n";
8491+
(void)valueOfTok(code, "x");
84238492
}
84248493

84258494
void valueFlowCrashConstructorInitialization() { // #9577

0 commit comments

Comments
 (0)