Skip to content

Commit 255dc04

Browse files
authored
Fix 10331: wrong conditional value after assignment+return (#3461)
1 parent 47ea670 commit 255dc04

4 files changed

Lines changed: 69 additions & 5 deletions

File tree

lib/forwardanalyzer.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
#include <tuple>
1313
#include <utility>
1414

15+
struct OnExit {
16+
std::function<void()> f;
17+
18+
~OnExit() {
19+
f();
20+
}
21+
};
22+
1523
struct ForwardTraversal {
1624
enum class Progress { Continue, Break, Skip };
1725
enum class Terminate { None, Bail, Escape, Modified, Inconclusive, Conditional };
@@ -25,6 +33,7 @@ struct ForwardTraversal {
2533
bool analyzeTerminate;
2634
Analyzer::Terminate terminate = Analyzer::Terminate::None;
2735
bool forked = false;
36+
std::vector<Token*> loopEnds = {};
2837

2938
Progress Break(Analyzer::Terminate t = Analyzer::Terminate::None) {
3039
if ((!analyzeOnly || analyzeTerminate) && t != Analyzer::Terminate::None)
@@ -85,9 +94,15 @@ struct ForwardTraversal {
8594

8695
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
8796
Progress traverseTok(T* tok, std::function<Progress(T*)> f, bool traverseUnknown, T** out = nullptr) {
88-
if (Token::Match(tok, "asm|goto|continue|setjmp|longjmp"))
89-
return Break();
90-
else if (Token::Match(tok, "return|throw") || isEscapeFunction(tok, &settings->library)) {
97+
if (Token::Match(tok, "asm|goto|setjmp|longjmp"))
98+
return Break(Analyzer::Terminate::Bail);
99+
else if (Token::simpleMatch(tok, "continue")) {
100+
if (loopEnds.empty())
101+
return Break(Analyzer::Terminate::Escape);
102+
// If we are in a loop then jump to the end
103+
if (out)
104+
*out = loopEnds.back();
105+
} else if (Token::Match(tok, "return|throw") || isEscapeFunction(tok, &settings->library)) {
91106
traverseRecursive(tok->astOperand1(), f, traverseUnknown);
92107
traverseRecursive(tok->astOperand2(), f, traverseUnknown);
93108
return Break(Analyzer::Terminate::Escape);
@@ -361,6 +376,10 @@ struct ForwardTraversal {
361376
}
362377

363378
Progress updateInnerLoop(Token* endBlock, Token* stepTok, Token* condTok) {
379+
loopEnds.push_back(endBlock);
380+
OnExit oe{[&] {
381+
loopEnds.pop_back();
382+
}};
364383
if (endBlock && updateScope(endBlock) == Progress::Break)
365384
return Break();
366385
if (stepTok && updateRecursive(stepTok) == Progress::Break)
@@ -632,7 +651,7 @@ struct ForwardTraversal {
632651
}
633652
actions |= (thenBranch.action | elseBranch.action);
634653
if (bail)
635-
return Break();
654+
return Break(Analyzer::Terminate::Bail);
636655
if (thenBranch.isDead() && elseBranch.isDead()) {
637656
if (thenBranch.isModified() && elseBranch.isModified())
638657
return Break(Analyzer::Terminate::Modified);

lib/valueflow.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5313,6 +5313,7 @@ struct ConditionHandler {
53135313
startTokens[1] = top->link()->linkAt(1)->tokAt(2);
53145314

53155315
int changeBlock = -1;
5316+
int bailBlock = -1;
53165317

53175318
for (int i = 0; i < 2; i++) {
53185319
const Token* const startToken = startTokens[i];
@@ -5326,6 +5327,9 @@ struct ConditionHandler {
53265327
deadBranch[i] = r.terminate == Analyzer::Terminate::Escape;
53275328
if (r.action.isModified() && !deadBranch[i])
53285329
changeBlock = i;
5330+
if (r.terminate != Analyzer::Terminate::None && r.terminate != Analyzer::Terminate::Escape &&
5331+
r.terminate != Analyzer::Terminate::Modified)
5332+
bailBlock = i;
53295333
changeKnownToPossible(values);
53305334
}
53315335
if (changeBlock >= 0 && !Token::simpleMatch(top->previous(), "while (")) {
@@ -5336,6 +5340,13 @@ struct ConditionHandler {
53365340
"valueFlowAfterCondition: " + cond.vartok->expressionString() +
53375341
" is changed in conditional block");
53385342
return;
5343+
} else if (bailBlock >= 0) {
5344+
if (settings->debugwarnings)
5345+
bailout(tokenlist,
5346+
errorLogger,
5347+
startTokens[bailBlock]->link(),
5348+
"valueFlowAfterCondition: bailing in conditional block");
5349+
return;
53395350
}
53405351

53415352
// After conditional code..

test/testnullpointer.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class TestNullPointer : public TestFixture {
121121
TEST_CASE(nullpointer79); // #10400
122122
TEST_CASE(nullpointer80); // #10410
123123
TEST_CASE(nullpointer81); // #8724
124+
TEST_CASE(nullpointer82); // #10331
124125
TEST_CASE(nullpointer_addressOf); // address of
125126
TEST_CASE(nullpointerSwitch); // #2626
126127
TEST_CASE(nullpointer_cast); // #4692
@@ -2474,6 +2475,26 @@ class TestNullPointer : public TestFixture {
24742475
ASSERT_EQUALS("", errout.str());
24752476
}
24762477

2478+
void nullpointer82() // #10331
2479+
{
2480+
check("bool g();\n"
2481+
"int* h();\n"
2482+
"void f(int* ptr) {\n"
2483+
" if (!ptr) {\n"
2484+
" if (g())\n"
2485+
" goto done;\n"
2486+
" ptr = h();\n"
2487+
" if (!ptr)\n"
2488+
" return;\n"
2489+
" }\n"
2490+
" if (*ptr == 1)\n"
2491+
" return;\n"
2492+
"\n"
2493+
"done:\n"
2494+
"}\n");
2495+
ASSERT_EQUALS("", errout.str());
2496+
}
2497+
24772498
void nullpointer_addressOf() { // address of
24782499
check("void f() {\n"
24792500
" struct X *x = 0;\n"

test/testvalueflow.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1703,7 +1703,8 @@ class TestValueFlow : public TestFixture {
17031703
" if (x==123){}\n"
17041704
"}");
17051705
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
1706-
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n",
1706+
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n"
1707+
"[test.cpp:2]: (debug) valueflow.cpp::(valueFlow) bailout: valueFlowAfterCondition: bailing in conditional block\n",
17071708
errout.str());
17081709

17091710
// #5721 - FP
@@ -2952,6 +2953,18 @@ class TestValueFlow : public TestFixture {
29522953
" return 0;\n"
29532954
"}\n";
29542955
ASSERT_EQUALS(true, testValueOfXKnown(code, 5U, 1));
2956+
2957+
code = "int f(int x) {\n"
2958+
" if (x == 1) {\n"
2959+
" for(int i=0;i<1;i++) {\n"
2960+
" if (x == 1)\n"
2961+
" continue;\n"
2962+
" }\n"
2963+
" }\n"
2964+
" return x;\n"
2965+
"}\n";
2966+
ASSERT_EQUALS(true, testValueOfX(code, 8U, 1));
2967+
ASSERT_EQUALS(false, testValueOfXImpossible(code, 8U, 1));
29552968
}
29562969

29572970
void valueFlowAfterConditionExpr() {

0 commit comments

Comments
 (0)