Fix 10326: Regression: ValueFlow; Wrong Uninit value after do while (#3312)

This commit is contained in:
Paul Fultz II 2021-07-03 02:12:26 -05:00 committed by GitHub
parent fc90598077
commit fb9d659e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 6 deletions

View File

@ -374,10 +374,23 @@ struct ForwardTraversal {
Token* endBlock, Token* endBlock,
Token* condTok, Token* condTok,
Token* initTok = nullptr, Token* initTok = nullptr,
Token* stepTok = nullptr) { Token* stepTok = nullptr,
bool exit = false) {
if (initTok && updateRecursive(initTok) == Progress::Break) if (initTok && updateRecursive(initTok) == Progress::Break)
return Break(); return Break();
const bool isDoWhile = precedes(endBlock, condTok); const bool isDoWhile = precedes(endBlock, condTok);
bool checkThen = true;
bool checkElse = false;
if (condTok && !Token::simpleMatch(condTok, ":"))
std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->link()->previous() : nullptr);
if (checkElse && exit)
return Progress::Continue;
// do while(false) is not really a loop
if (checkElse && isDoWhile) {
if (updateRange(endBlock->link(), endBlock) == Progress::Break)
return Break();
return updateRecursive(condTok);
}
Analyzer::Action bodyAnalysis = analyzeScope(endBlock); Analyzer::Action bodyAnalysis = analyzeScope(endBlock);
Analyzer::Action allAnalysis = bodyAnalysis; Analyzer::Action allAnalysis = bodyAnalysis;
if (condTok) if (condTok)
@ -392,14 +405,11 @@ struct ForwardTraversal {
if (!analyzer->lowerToPossible()) if (!analyzer->lowerToPossible())
return Break(Analyzer::Terminate::Bail); return Break(Analyzer::Terminate::Bail);
} }
bool checkThen = true;
bool checkElse = false;
if (condTok && !Token::simpleMatch(condTok, ":")) { if (condTok && !Token::simpleMatch(condTok, ":")) {
if (!isDoWhile || (!bodyAnalysis.isModified() && !bodyAnalysis.isIdempotent())) if (!isDoWhile || (!bodyAnalysis.isModified() && !bodyAnalysis.isIdempotent()))
if (updateRecursive(condTok) == Progress::Break) if (updateRecursive(condTok) == Progress::Break)
return Break(); return Break();
// TODO: Check cond first before lowering
std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->link()->previous() : nullptr);
} }
// condition is false, we don't enter the loop // condition is false, we don't enter the loop
if (checkElse) if (checkElse)
@ -442,6 +452,15 @@ struct ForwardTraversal {
return Progress::Continue; return Progress::Continue;
} }
Progress updateLoopExit(const Token* endToken,
Token* endBlock,
Token* condTok,
Token* initTok = nullptr,
Token* stepTok = nullptr)
{
return updateLoop(endToken, endBlock, condTok, initTok, stepTok, true);
}
Progress updateScope(Token* endBlock) { Progress updateScope(Token* endBlock) {
if (forked) if (forked)
analyzer->forkScope(endBlock); analyzer->forkScope(endBlock);
@ -528,7 +547,7 @@ struct ForwardTraversal {
} else if (scope->type == Scope::eLambda) { } else if (scope->type == Scope::eLambda) {
return Break(); return Break();
} else if (scope->type == Scope::eDo && Token::simpleMatch(tok, "} while (")) { } else if (scope->type == Scope::eDo && Token::simpleMatch(tok, "} while (")) {
if (updateLoop(end, tok, tok->tokAt(2)->astOperand2()) == Progress::Break) if (updateLoopExit(end, tok, tok->tokAt(2)->astOperand2()) == Progress::Break)
return Break(); return Break();
tok = tok->linkAt(2); tok = tok->linkAt(2);
} else if (Token::simpleMatch(tok->next(), "else {")) { } else if (Token::simpleMatch(tok->next(), "else {")) {

View File

@ -114,6 +114,7 @@ private:
TEST_CASE(nullpointer71); // #10178 TEST_CASE(nullpointer71); // #10178
TEST_CASE(nullpointer72); // #10215 TEST_CASE(nullpointer72); // #10215
TEST_CASE(nullpointer73); // #10321 TEST_CASE(nullpointer73); // #10321
TEST_CASE(nullpointer74);
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
@ -2289,6 +2290,45 @@ private:
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:10]: (warning) Either the condition 'ptr!=nullptr' is redundant or there is possible null pointer dereference: ptr.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:10]: (warning) Either the condition 'ptr!=nullptr' is redundant or there is possible null pointer dereference: ptr.\n", errout.str());
} }
void nullpointer74() {
check("struct d {\n"
" d* e();\n"
"};\n"
"void g(d* f) {\n"
" do {\n"
" f = f->e();\n"
" if (f) {}\n"
" } while (0);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("struct d {\n"
" d* e();\n"
"};\n"
"void g(d* f, int i) {\n"
" do {\n"
" i--;\n"
" f = f->e();\n"
" if (f) {}\n"
" } while (i > 0);\n"
"}\n");
ASSERT_EQUALS(
"[test.cpp:8] -> [test.cpp:7]: (warning) Either the condition 'f' is redundant or there is possible null pointer dereference: f.\n",
errout.str());
check("struct d {\n"
" d* e();\n"
"};\n"
"void g(d* f, int i) {\n"
" do {\n"
" i--;\n"
" f = f->e();\n"
" if (f) {}\n"
" } while (f && i > 0);\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

@ -4845,6 +4845,17 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// #10326
valueFlowUninit("void foo() {\n"
" int cnt;\n"
" do {\n"
" cnt = 32 ;\n"
" }\n"
" while ( 0 ) ;\n"
" if (cnt != 0) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// #10327 - avoid extra warnings for uninitialized variable // #10327 - avoid extra warnings for uninitialized variable
valueFlowUninit("void dowork( int me ) {\n" valueFlowUninit("void dowork( int me ) {\n"
" if ( me == 0 ) {}\n" // <- not uninitialized " if ( me == 0 ) {}\n" // <- not uninitialized