diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 81e1ddc32..402d6c08b 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -232,6 +232,25 @@ static bool frontIs(const std::vector& v, bool i) return !i; } +// If the scope is a non-range for loop +static bool isBasicForLoop(const Token* tok) +{ + if (!tok) + return false; + if (Token::simpleMatch(tok, "}")) + return isBasicForLoop(tok->link()); + if (!Token::simpleMatch(tok->previous(), ") {")) + return false; + const Token* start = tok->linkAt(-1); + if (!start) + return false; + if (!Token::simpleMatch(start->previous(), "for (")) + return false; + if (!Token::simpleMatch(start->astOperand2(), ";")) + return false; + return true; +} + void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then) { auto eval = [&](const Token* t) -> std::vector { @@ -343,8 +362,10 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok if (tok2->str() == "{") { if (indentlevel <= 0) { - // Keep progressing with anonymous/do scopes - if (!Token::Match(tok2->previous(), "do|; {")) + const Token* cond = getCondTokFromEnd(tok2->link()); + // Keep progressing with anonymous/do scopes and always true branches + if (!Token::Match(tok2->previous(), "do|; {") && !conditionIsTrue(cond, state) && + (cond || !isBasicForLoop(tok2))) break; } else --indentlevel; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 0760df72a..806110e4f 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -104,6 +104,7 @@ private: TEST_CASE(valueFlowForwardTryCatch); TEST_CASE(valueFlowForwardInconclusiveImpossible); TEST_CASE(valueFlowForwardConst); + TEST_CASE(valueFlowForwardAfterCondition); TEST_CASE(valueFlowFwdAnalysis); @@ -3685,6 +3686,56 @@ private: ASSERT_EQUALS(true, testValueOfXKnown(code, 8U, 3)); } + void valueFlowForwardAfterCondition() + { + const char* code; + + code = "int g();\n" + "void f() {\n" + " int x = 3;\n" + " int kk = 11;\n" + " for (;;) {\n" + " if (kk > 10) {\n" + " kk = 0;\n" + " x = g();\n" + " }\n" + " kk++;\n" + " int a = x;\n" + " }\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 11U, 3)); + + code = "int g();\n" + "void f() {\n" + " int x = 3;\n" + " int kk = 11;\n" + " while (true) {\n" + " if (kk > 10) {\n" + " kk = 0;\n" + " x = g();\n" + " }\n" + " kk++;\n" + " int a = x;\n" + " }\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 11U, 3)); + + code = "int g();\n" + "void f() {\n" + " int x = 3;\n" + " int kk = 11;\n" + " if (true) {\n" + " if (kk > 10) {\n" + " kk = 0;\n" + " x = g();\n" + " }\n" + " kk++;\n" + " int a = x;\n" + " }\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 11U, 3)); + } + void valueFlowRightShift() { const char *code; /* Set some temporary fixed values to simplify testing */