Skip to content

Commit fb9d659

Browse files
authored
Fix 10326: Regression: ValueFlow; Wrong Uninit value after do while (#3312)
1 parent fc90598 commit fb9d659

3 files changed

Lines changed: 76 additions & 6 deletions

File tree

lib/forwardanalyzer.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,23 @@ struct ForwardTraversal {
374374
Token* endBlock,
375375
Token* condTok,
376376
Token* initTok = nullptr,
377-
Token* stepTok = nullptr) {
377+
Token* stepTok = nullptr,
378+
bool exit = false) {
378379
if (initTok && updateRecursive(initTok) == Progress::Break)
379380
return Break();
380381
const bool isDoWhile = precedes(endBlock, condTok);
382+
bool checkThen = true;
383+
bool checkElse = false;
384+
if (condTok && !Token::simpleMatch(condTok, ":"))
385+
std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->link()->previous() : nullptr);
386+
if (checkElse && exit)
387+
return Progress::Continue;
388+
// do while(false) is not really a loop
389+
if (checkElse && isDoWhile) {
390+
if (updateRange(endBlock->link(), endBlock) == Progress::Break)
391+
return Break();
392+
return updateRecursive(condTok);
393+
}
381394
Analyzer::Action bodyAnalysis = analyzeScope(endBlock);
382395
Analyzer::Action allAnalysis = bodyAnalysis;
383396
if (condTok)
@@ -392,14 +405,11 @@ struct ForwardTraversal {
392405
if (!analyzer->lowerToPossible())
393406
return Break(Analyzer::Terminate::Bail);
394407
}
395-
bool checkThen = true;
396-
bool checkElse = false;
408+
397409
if (condTok && !Token::simpleMatch(condTok, ":")) {
398410
if (!isDoWhile || (!bodyAnalysis.isModified() && !bodyAnalysis.isIdempotent()))
399411
if (updateRecursive(condTok) == Progress::Break)
400412
return Break();
401-
// TODO: Check cond first before lowering
402-
std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->link()->previous() : nullptr);
403413
}
404414
// condition is false, we don't enter the loop
405415
if (checkElse)
@@ -442,6 +452,15 @@ struct ForwardTraversal {
442452
return Progress::Continue;
443453
}
444454

455+
Progress updateLoopExit(const Token* endToken,
456+
Token* endBlock,
457+
Token* condTok,
458+
Token* initTok = nullptr,
459+
Token* stepTok = nullptr)
460+
{
461+
return updateLoop(endToken, endBlock, condTok, initTok, stepTok, true);
462+
}
463+
445464
Progress updateScope(Token* endBlock) {
446465
if (forked)
447466
analyzer->forkScope(endBlock);
@@ -528,7 +547,7 @@ struct ForwardTraversal {
528547
} else if (scope->type == Scope::eLambda) {
529548
return Break();
530549
} else if (scope->type == Scope::eDo && Token::simpleMatch(tok, "} while (")) {
531-
if (updateLoop(end, tok, tok->tokAt(2)->astOperand2()) == Progress::Break)
550+
if (updateLoopExit(end, tok, tok->tokAt(2)->astOperand2()) == Progress::Break)
532551
return Break();
533552
tok = tok->linkAt(2);
534553
} else if (Token::simpleMatch(tok->next(), "else {")) {

test/testnullpointer.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class TestNullPointer : public TestFixture {
114114
TEST_CASE(nullpointer71); // #10178
115115
TEST_CASE(nullpointer72); // #10215
116116
TEST_CASE(nullpointer73); // #10321
117+
TEST_CASE(nullpointer74);
117118
TEST_CASE(nullpointer_addressOf); // address of
118119
TEST_CASE(nullpointerSwitch); // #2626
119120
TEST_CASE(nullpointer_cast); // #4692
@@ -2289,6 +2290,45 @@ class TestNullPointer : public TestFixture {
22892290
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());
22902291
}
22912292

2293+
void nullpointer74() {
2294+
check("struct d {\n"
2295+
" d* e();\n"
2296+
"};\n"
2297+
"void g(d* f) {\n"
2298+
" do {\n"
2299+
" f = f->e();\n"
2300+
" if (f) {}\n"
2301+
" } while (0);\n"
2302+
"}\n");
2303+
ASSERT_EQUALS("", errout.str());
2304+
2305+
check("struct d {\n"
2306+
" d* e();\n"
2307+
"};\n"
2308+
"void g(d* f, int i) {\n"
2309+
" do {\n"
2310+
" i--;\n"
2311+
" f = f->e();\n"
2312+
" if (f) {}\n"
2313+
" } while (i > 0);\n"
2314+
"}\n");
2315+
ASSERT_EQUALS(
2316+
"[test.cpp:8] -> [test.cpp:7]: (warning) Either the condition 'f' is redundant or there is possible null pointer dereference: f.\n",
2317+
errout.str());
2318+
2319+
check("struct d {\n"
2320+
" d* e();\n"
2321+
"};\n"
2322+
"void g(d* f, int i) {\n"
2323+
" do {\n"
2324+
" i--;\n"
2325+
" f = f->e();\n"
2326+
" if (f) {}\n"
2327+
" } while (f && i > 0);\n"
2328+
"}\n");
2329+
ASSERT_EQUALS("", errout.str());
2330+
}
2331+
22922332
void nullpointer_addressOf() { // address of
22932333
check("void f() {\n"
22942334
" struct X *x = 0;\n"

test/testuninitvar.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4845,6 +4845,17 @@ class TestUninitVar : public TestFixture {
48454845
"}\n");
48464846
ASSERT_EQUALS("", errout.str());
48474847

4848+
// #10326
4849+
valueFlowUninit("void foo() {\n"
4850+
" int cnt;\n"
4851+
" do {\n"
4852+
" cnt = 32 ;\n"
4853+
" }\n"
4854+
" while ( 0 ) ;\n"
4855+
" if (cnt != 0) {}\n"
4856+
"}\n");
4857+
ASSERT_EQUALS("", errout.str());
4858+
48484859
// #10327 - avoid extra warnings for uninitialized variable
48494860
valueFlowUninit("void dowork( int me ) {\n"
48504861
" if ( me == 0 ) {}\n" // <- not uninitialized

0 commit comments

Comments
 (0)