Skip to content

Commit 9cecc84

Browse files
authored
Fix 10570: Improve check; condition then pointer dereference, different pointers (#4216)
* Try to use after assign in loop * Update valueflow forward to handle init tokens * Fix tests * Make test TODO * Format * Add tests * Format * Fix ubsan error * Use simpleMatch
1 parent de51ebb commit 9cecc84

5 files changed

Lines changed: 55 additions & 10 deletions

File tree

lib/forwardanalyzer.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,23 @@ struct ForwardTraversal {
575575
tok = nextAfterAstRightmostLeaf(assignTok);
576576
if (!tok)
577577
return Break();
578-
} else if (tok->str() == "break") {
578+
} else if (Token::simpleMatch(tok, ") {") && Token::Match(tok->link()->previous(), "for|while (")) {
579+
// In the middle of a loop structure so bail
580+
return Break(Analyzer::Terminate::Bail);
581+
} else if (tok->str() == ";" && tok->astParent()) {
582+
Token* top = tok->astTop();
583+
if (top && Token::Match(top->previous(), "for|while (") && Token::simpleMatch(top->link(), ") {")) {
584+
Token* endCond = top->link();
585+
Token* endBlock = endCond->linkAt(1);
586+
Token* condTok = getCondTok(top);
587+
Token* stepTok = getStepTok(top);
588+
// The semicolon should belong to the initTok otherwise something went wrong, so just bail
589+
if (tok->astOperand2() != condTok && !Token::simpleMatch(tok->astOperand2(), ";"))
590+
return Break(Analyzer::Terminate::Bail);
591+
if (updateLoop(end, endBlock, condTok, nullptr, stepTok) == Progress::Break)
592+
return Break();
593+
}
594+
} else if (tok->str() == "break") {
579595
const Token *scopeEndToken = findNextTokenFromBreak(tok);
580596
if (!scopeEndToken)
581597
return Break();
@@ -640,7 +656,8 @@ struct ForwardTraversal {
640656
} else if (Token::simpleMatch(tok->next(), "else {")) {
641657
tok = tok->linkAt(2);
642658
}
643-
} else if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for (") && Token::simpleMatch(tok->next()->link(), ") {")) {
659+
} else if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for (") &&
660+
Token::simpleMatch(tok->next()->link(), ") {")) {
644661
Token* endCond = tok->next()->link();
645662
Token* endBlock = endCond->next()->link();
646663
Token* condTok = getCondTok(tok);

lib/valueflow.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
#include <array>
106106
#include <cassert>
107107
#include <climits>
108+
#include <cmath>
108109
#include <cstdlib>
109110
#include <cstring>
110111
#include <exception>
@@ -918,9 +919,9 @@ static void setTokenValue(Token* tok,
918919
const double floatValue1 = value1.isFloatValue() ? value1.floatValue : value1.intvalue;
919920
const double floatValue2 = value2.isFloatValue() ? value2.floatValue : value2.intvalue;
920921
const MathLib::bigint intValue1 =
921-
value1.isFloatValue() ? static_cast<MathLib::bigint>(value1.floatValue) : value1.intvalue;
922+
value1.isFloatValue() ? std::llround(value1.floatValue) : value1.intvalue;
922923
const MathLib::bigint intValue2 =
923-
value2.isFloatValue() ? static_cast<MathLib::bigint>(value2.floatValue) : value2.intvalue;
924+
value2.isFloatValue() ? std::llround(value2.floatValue) : value2.intvalue;
924925
if ((value1.isFloatValue() || value2.isFloatValue()) && Token::Match(parent, "&|^|%|<<|>>|==|!=|%or%"))
925926
continue;
926927
if (Token::Match(parent, "==|!=")) {
@@ -5444,7 +5445,10 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
54445445
std::unordered_map<nonneg int, std::unordered_set<nonneg int>> backAssigns;
54455446
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
54465447
// Assignment
5447-
if ((tok->str() != "=" && !isVariableInit(tok)) || (tok->astParent()))
5448+
if (tok->str() != "=" && !isVariableInit(tok))
5449+
continue;
5450+
5451+
if (tok->astParent() && !(tok->astParent()->str() == ";" && astIsLHS(tok)))
54485452
continue;
54495453

54505454
// Lhs should be a variable

test/testbufferoverrun.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2380,7 +2380,8 @@ class TestBufferOverrun : public TestFixture {
23802380
" some_condition ? 0 : a[i-1];\n"
23812381
" }\n"
23822382
"}");
2383-
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Array index -1 is out of bounds.\n", "", errout.str());
2383+
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[10]' accessed at index -1, which is out of bounds.\n",
2384+
errout.str());
23842385

23852386
check("void f() {\n"
23862387
" int a[10];\n"

test/teststl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2518,13 +2518,16 @@ class TestStl : public TestFixture {
25182518
" {\n"
25192519
" if (a) {\n"
25202520
" if (b)\n"
2521-
" foo.erase(it);\n"
2521+
" foo.erase(it);\n" // <- TODO: erase shound't cause inconclusive valueflow
25222522
" else\n"
25232523
" *it = 0;\n"
25242524
" }\n"
25252525
" }\n"
25262526
"}");
2527-
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:7] -> [test.cpp:8] -> [test.cpp:8] -> [test.cpp:7] -> [test.cpp:5] -> [test.cpp:9] -> [test.cpp:3] -> [test.cpp:5]: (error) Using iterator to local container 'foo' that may be invalid.\n", errout.str());
2527+
TODO_ASSERT_EQUALS(
2528+
"[test.cpp:5] -> [test.cpp:7] -> [test.cpp:8] -> [test.cpp:8] -> [test.cpp:7] -> [test.cpp:5] -> [test.cpp:9] -> [test.cpp:3] -> [test.cpp:5]: (error) Using iterator to local container 'foo' that may be invalid.\n",
2529+
"[test.cpp:5] -> [test.cpp:7] -> [test.cpp:8] -> [test.cpp:8] -> [test.cpp:7] -> [test.cpp:5] -> [test.cpp:9] -> [test.cpp:3] -> [test.cpp:5]: (error, inconclusive) Using iterator to local container 'foo' that may be invalid.\n",
2530+
errout.str());
25282531
}
25292532

25302533
void eraseGoto() {

test/testvalueflow.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,23 @@ class TestValueFlow : public TestFixture {
26032603
" }\n"
26042604
"};";
26052605
ASSERT_EQUALS(true, testValueOfX(code, 6U, 10));
2606+
2607+
code = "void f(int i) {\n"
2608+
" if (i == 3) {}\n"
2609+
" for(int x = i;\n"
2610+
" x;\n"
2611+
" x++) {}\n"
2612+
"}\n";
2613+
ASSERT_EQUALS(true, testValueOfX(code, 4U, 3));
2614+
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, 3));
2615+
2616+
code = "void f() {\n"
2617+
" for(int x = 3;\n"
2618+
" x;\n"
2619+
" x++) {}\n"
2620+
"}\n";
2621+
ASSERT_EQUALS(true, testValueOfX(code, 4U, 3));
2622+
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, 3));
26062623
}
26072624

26082625
void valueFlowAfterSwap()
@@ -3920,7 +3937,10 @@ class TestValueFlow : public TestFixture {
39203937
"void foo(struct S s) {\n"
39213938
" for (s.x = 0; s.x < 127; s.x++) {}\n"
39223939
"}";
3923-
values = removeImpossible(tokenValues(code, "<")); // TODO: comparison can be true or false
3940+
values = removeImpossible(tokenValues(code, "<"));
3941+
values.remove_if([&](const ValueFlow::Value& v) {
3942+
return !v.isKnown();
3943+
});
39243944
ASSERT_EQUALS(true, values.empty());
39253945
}
39263946

@@ -4062,7 +4082,7 @@ class TestValueFlow : public TestFixture {
40624082
" for (int x = 0; x < 10 && y = do_something();)\n"
40634083
" x;\n"
40644084
"}";
4065-
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 4U, 0));
4085+
ASSERT_EQUALS(true, testValueOfX(code, 4U, 0));
40664086

40674087
code = "void f() {\n"
40684088
" int x,y;\n"

0 commit comments

Comments
 (0)