From b00e38c2eabf37a169712552c1684c2dbc5c1415 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Mon, 13 Apr 2026 15:29:45 +0200 Subject: [PATCH] Fix #8192: FN condition always false in for loop condition When a for loop's condition is impossible given the initial value (e.g. `for (int i = 0; i > 10; i++)`), cppcheck was not emitting a knownConditionTrueFalse warning. Fix by populating memory1, memory2 and memoryAfter with the init state when the condition is immediately false (and no error occured). We can then set the value for the condition token and thus emit a knownConditionTrueFalse warning. Signed-off-by: Francois Berder --- lib/valueflow.cpp | 55 ++++++++++++++++++++++++++++-------------- test/testcondition.cpp | 2 +- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6db9ba6d1e3..b2230b242ef 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5175,8 +5175,18 @@ static bool valueFlowForLoop2(const Token *tok, if (error) return false; execute(secondExpression, programMemory, &result, &error, settings); - if (result == 0) // 2nd expression is false => no looping + if (result == 0) { + if (!error) { // 2nd expression is false => no looping + ProgramMemory startMemory(programMemory); + ProgramMemory endMemory(programMemory); + + memory1.swap(startMemory); + memory2.swap(endMemory); + memoryAfter.swap(programMemory); + return true; + } return false; + } if (error) { // If a variable is reassigned in second expression, return false bool reassign = false; @@ -5382,23 +5392,32 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s } else { ProgramMemory mem1, mem2, memAfter; if (valueFlowForLoop2(tok, mem1, mem2, memAfter, settings)) { - for (const auto& p : mem1) { - if (!p.second.isIntValue()) - continue; - if (p.second.isImpossible()) - continue; - if (p.first.tok->varId() == 0) - continue; - valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); - } - for (const auto& p : mem2) { - if (!p.second.isIntValue()) - continue; - if (p.second.isImpossible()) - continue; - if (p.first.tok->varId() == 0) - continue; - valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + if (mem1 == memAfter) { // #8192 check if loop never runs + Token* condTok = getCondTok(tok); + if (condTok && !condTok->hasKnownIntValue()) { + ValueFlow::Value v(0); + v.setKnown(); + ValueFlow::setTokenValue(condTok, std::move(v), settings); + } + } else { + for (const auto& p : mem1) { + if (!p.second.isIntValue()) + continue; + if (p.second.isImpossible()) + continue; + if (p.first.tok->varId() == 0) + continue; + valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + } + for (const auto& p : mem2) { + if (!p.second.isIntValue()) + continue; + if (p.second.isImpossible()) + continue; + if (p.first.tok->varId() == 0) + continue; + valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + } } for (const auto& p : memAfter) { if (!p.second.isIntValue()) diff --git a/test/testcondition.cpp b/test/testcondition.cpp index afbcf14ca6d..ff4a1cdf086 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5639,7 +5639,7 @@ class TestCondition : public TestFixture { check("void f() {\n" // #8192 " for (int i = 0; i > 10; ++i) {}\n" "}\n"); - TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i>10' is always false\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:2:23]: (style) Condition 'i>10' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " for (int i = 1000; i < 20; ++i) {}\n"