Fix 10400: FP nullPointer - for loop condition (#3417)

This commit is contained in:
Paul Fultz II 2021-08-25 13:33:41 -05:00 committed by GitHub
parent 11916171fe
commit 8aa37218c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 10 deletions

View File

@ -411,6 +411,8 @@ struct ForwardTraversal {
if (updateRecursive(condTok) == Progress::Break) if (updateRecursive(condTok) == Progress::Break)
return 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 // condition is false, we don't enter the loop
if (checkElse) if (checkElse)
return Progress::Continue; return Progress::Continue;

View File

@ -153,16 +153,18 @@ bool conditionIsTrue(const Token *condition, const ProgramMemory &programMemory)
return !error && result == 1; return !error && result == 1;
} }
static bool frontIs(const std::vector<MathLib::bigint>& 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) void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then)
{ {
if (Token::Match(tok, "==|>=|<=|<|>|!=")) { auto eval = [&](const Token* t) -> std::vector<MathLib::bigint> {
if (then && !Token::Match(tok, "==|>=|<=|<|>"))
return;
if (!then && !Token::Match(tok, "<|>|!="))
return;
ValueFlow::Value truevalue;
ValueFlow::Value falsevalue;
const Token* vartok = parseCompareInt(tok, truevalue, falsevalue, [&](const Token* t) -> std::vector<MathLib::bigint> {
if (t->hasKnownIntValue()) if (t->hasKnownIntValue())
return {t->values().front().intvalue}; return {t->values().front().intvalue};
MathLib::bigint result = 0; MathLib::bigint result = 0;
@ -171,7 +173,15 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
if (!error) if (!error)
return {result}; return {result};
return std::vector<MathLib::bigint>{}; return std::vector<MathLib::bigint>{};
}); };
if (Token::Match(tok, "==|>=|<=|<|>|!=")) {
if (then && !Token::Match(tok, "==|>=|<=|<|>"))
return;
if (!then && !Token::Match(tok, "<|>|!="))
return;
ValueFlow::Value truevalue;
ValueFlow::Value falsevalue;
const Token* vartok = parseCompareInt(tok, truevalue, falsevalue, eval);
if (!vartok) if (!vartok)
return; return;
if (vartok->exprId() == 0) if (vartok->exprId() == 0)
@ -194,6 +204,15 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
} else if (!then && Token::simpleMatch(tok, "||")) { } else if (!then && Token::simpleMatch(tok, "||")) {
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then);
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then);
} else if (Token::Match(tok, "&&|%oror%")) {
std::vector<MathLib::bigint> lhs = eval(tok->astOperand1());
std::vector<MathLib::bigint> 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) { } else if (tok->exprId() > 0) {
if (then && !astIsPointer(tok) && !astIsBool(tok)) if (then && !astIsPointer(tok) && !astIsBool(tok))
return; return;

View File

@ -118,6 +118,7 @@ private:
TEST_CASE(nullpointer76); // #10408 TEST_CASE(nullpointer76); // #10408
TEST_CASE(nullpointer77); TEST_CASE(nullpointer77);
TEST_CASE(nullpointer78); // #7802 TEST_CASE(nullpointer78); // #7802
TEST_CASE(nullpointer79); // #10400
TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointer_addressOf); // address of
TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointerSwitch); // #2626
TEST_CASE(nullpointer_cast); // #4692 TEST_CASE(nullpointer_cast); // #4692
@ -2418,6 +2419,18 @@ private:
ASSERT_EQUALS("[test.cpp:6]: (error) Null pointer dereference: *pp\n", errout.str()); 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 void nullpointer_addressOf() { // address of
check("void f() {\n" check("void f() {\n"
" struct X *x = 0;\n" " struct X *x = 0;\n"

View File

@ -3125,6 +3125,20 @@ private:
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0)); ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
ASSERT_EQUALS(false, testValueOfX(code, 4U, 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() { void valueFlowForwardModifiedVariables() {