From 2209cc342ce37b6dc834a40d4280bdcd5d9c3da3 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 | 60 +++++++++++++++++++++++++++++------------- test/testcondition.cpp | 2 +- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 0f1c8a20ce7..262ee8d0a8f 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5175,8 +5175,21 @@ 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 definitely false => no looping + ProgramMemory startMemory(programMemory); + ProgramMemory endMemory(programMemory); + + if (memory1) + memory1->swap(startMemory); + if (memory2) + memory2->swap(endMemory); + if (memoryAfter) + memoryAfter->swap(programMemory); + return true; + } return false; + } if (error) { // If a variable is reassigned in second expression, return false bool reassign = false; @@ -5385,23 +5398,34 @@ 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"