diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index dd23afbba..25634f2c1 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -411,6 +411,8 @@ struct ForwardTraversal { if (updateRecursive(condTok) == Progress::Break) return Break(); } + if (!checkThen && !checkElse && !isDoWhile && analyzer->stopOnCondition(condTok) && stopUpdates()) + return Break(Analyzer::Terminate::Conditional); // condition is false, we don't enter the loop if (checkElse) return Progress::Continue; diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 8aee0791b..5fe3c0cce 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -153,8 +153,27 @@ bool conditionIsTrue(const Token *condition, const ProgramMemory &programMemory) return !error && result == 1; } +static bool frontIs(const std::vector& v, bool i) +{ + if (v.empty()) + return false; + if (v.front()) + return i; + return !i; +} + void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then) { + auto eval = [&](const Token* t) -> std::vector { + if (t->hasKnownIntValue()) + return {t->values().front().intvalue}; + MathLib::bigint result = 0; + bool error = false; + execute(t, &pm, &result, &error); + if (!error) + return {result}; + return std::vector{}; + }; if (Token::Match(tok, "==|>=|<=|<|>|!=")) { if (then && !Token::Match(tok, "==|>=|<=|<|>")) return; @@ -162,16 +181,7 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke return; ValueFlow::Value truevalue; ValueFlow::Value falsevalue; - const Token* vartok = parseCompareInt(tok, truevalue, falsevalue, [&](const Token* t) -> std::vector { - if (t->hasKnownIntValue()) - return {t->values().front().intvalue}; - MathLib::bigint result = 0; - bool error = false; - execute(t, &pm, &result, &error); - if (!error) - return {result}; - return std::vector{}; - }); + const Token* vartok = parseCompareInt(tok, truevalue, falsevalue, eval); if (!vartok) return; if (vartok->exprId() == 0) @@ -194,6 +204,15 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke } else if (!then && Token::simpleMatch(tok, "||")) { programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + } else if (Token::Match(tok, "&&|%oror%")) { + std::vector lhs = eval(tok->astOperand1()); + std::vector rhs = eval(tok->astOperand2()); + if (lhs.empty() || rhs.empty()) { + if (frontIs(lhs, !then)) + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + if (frontIs(rhs, !then)) + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); + } } else if (tok->exprId() > 0) { if (then && !astIsPointer(tok) && !astIsBool(tok)) return; diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 10049dec8..c0e62a2ce 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -118,6 +118,7 @@ private: TEST_CASE(nullpointer76); // #10408 TEST_CASE(nullpointer77); TEST_CASE(nullpointer78); // #7802 + TEST_CASE(nullpointer79); // #10400 TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -2418,6 +2419,18 @@ private: ASSERT_EQUALS("[test.cpp:6]: (error) Null pointer dereference: *pp\n", errout.str()); } + void nullpointer79() // #10400 + { + check("void resize(size_t nF, size_t nT) {\n" + " double* pValues = nullptr;\n" + " if (nF > 0 && nT > 0)\n" + " pValues = new double[nF * nT];\n" + " for (size_t cc = 0; cc < nF * nT; ++cc)\n" + " pValues[cc] = 42;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index e17c5e725..c57875535 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -3125,6 +3125,20 @@ private: "}"; ASSERT_EQUALS(true, testValueOfX(code, 3U, 0)); ASSERT_EQUALS(false, testValueOfX(code, 4U, 0)); + + code = "int g();\n" + "int f(bool i, bool j) {\n" + " if (i && j) {}\n" + " else {\n" + " int x = 0;\n" + " if (i)\n" + " x = g();\n" + " return x;\n" + " }\n" + " return 0;\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfXKnown(code, 8U, 0)); + ASSERT_EQUALS(true, testValueOfX(code, 8U, 0)); } void valueFlowForwardModifiedVariables() {