diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index fdc47e231..41b791ed6 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -642,6 +642,23 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog } } +static void removeValues(std::list &values, const std::list &valuesToRemove) +{ + for (std::list::iterator it = values.begin(); it != values.end();) { + bool found = false; + for (std::list::const_iterator it2 = valuesToRemove.begin(); it2 != valuesToRemove.end(); ++it2) { + if (it->intvalue == it2->intvalue) { + found = true; + break; + } + } + if (found) + values.erase(it++); + else + it++; + } +} + static bool valueFlowForward(Token * const startToken, const Token * const endToken, const Variable * const var, @@ -710,18 +727,30 @@ static bool valueFlowForward(Token * const startToken, // conditional block of code that assigns variable.. else if (Token::Match(tok2, "%var% (") && Token::simpleMatch(tok2->linkAt(1), ") {")) { // Should scope be skipped because variable value is checked? - bool skip = false; + std::list truevalues; for (std::list::iterator it = values.begin(); it != values.end(); ++it) { - if (conditionIsFalse(tok2->next()->astOperand2(), getProgramMemory(tok2, varid, *it))) { - skip = true; - break; - } + if (!conditionIsFalse(tok2->next()->astOperand2(), getProgramMemory(tok2, varid, *it))) + truevalues.push_back(*it); } - if (skip) { - // goto '{' - tok2 = tok2->linkAt(1)->next(); + if (truevalues.size() != values.size()) { + // '{' + Token * const startToken1 = tok2->linkAt(1)->next(); + + valueFlowForward(startToken1->next(), + startToken1->link(), + var, + varid, + truevalues, + constValue, + tokenlist, + errorLogger, + settings); + + if (isVariableChanged(startToken1, startToken1->link(), varid)) + removeValues(values, truevalues); + // goto '}' - tok2 = tok2->link(); + tok2 = startToken1->link(); continue; } @@ -838,7 +867,7 @@ static bool valueFlowForward(Token * const startToken, if (tok3->varId() == varid) { std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) - setTokenValue(tok2, *it); + setTokenValue(tok3, *it); } else if (Token::Match(tok3, "++|--|?|:|;")) break; } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 8446d7d6d..7e74d0b01 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -128,8 +128,8 @@ private: "{\n" " while (tok);\n" " tok = tok->next();\n" - "}"); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (warning) Possible null pointer dereference: tok - otherwise it is redundant to check it against null.\n", errout.str()); + "}", true); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (warning, inconclusive) Possible null pointer dereference: tok - otherwise it is redundant to check it against null.\n", errout.str()); // #2681 { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index d56ceb1f0..3ae3f8c2a 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -788,6 +788,22 @@ private: "}"; ASSERT_EQUALS(false, testValueOfX(code, 4U, 0)); + code = "void f() {\n" // #6118 - FP + " int x = 0;\n" + " x = x & 0x1;\n" + " if (x == 0) { x = 2; }\n" + " y = 42 / x;\n" // <- x can't be 0 + "}"; + ASSERT_EQUALS(false, testValueOfX(code, 5U, 0)); + + code = "void f() {\n" // #6118 - FN + " int x = 0;\n" + " x = x & 0x1;\n" + " if (x == 0) { x += 2; }\n" + " y = 42 / x;\n" // <- x can be 2 + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 5U, 2)); + // multivariables code = "void f(int a) {\n" " int x = a;\n"