Skip to content

Commit c84628c

Browse files
committed
Fixed #8494 (False positive: serialization class overloads operator)
1 parent 7d5a1b1 commit c84628c

8 files changed

Lines changed: 89 additions & 28 deletions

File tree

lib/astutils.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,3 +625,26 @@ const Token *findLambdaEndToken(const Token *first)
625625
return tok->link();
626626
return nullptr;
627627
}
628+
629+
bool isLikelyStreamRead(bool cpp, const Token *op)
630+
{
631+
if (!cpp)
632+
return false;
633+
634+
if (Token::Match(op, ">> %name% >>|;")) {
635+
const Token *parent = op;
636+
while (Token::simpleMatch(parent->astParent(), ">>"))
637+
parent = parent->astParent();
638+
if (parent->astParent())
639+
return false;
640+
if (!parent->astOperand1() || !parent->astOperand2())
641+
return false;
642+
return (!parent->astOperand1()->valueType() || !parent->astOperand1()->valueType()->isIntegral());
643+
}
644+
645+
if (Token::Match(op, "& %name% ;") && !op->astParent() && op->astOperand1() && op->astOperand2() && (!op->astOperand1()->valueType() || !op->astOperand1()->valueType()->isIntegral()))
646+
return true;
647+
648+
return false;
649+
}
650+

lib/astutils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,11 @@ std::vector<const Token *> getArguments(const Token *ftok);
121121
*/
122122
const Token *findLambdaEndToken(const Token *first);
123123

124+
/**
125+
* do we see a likely write of rhs through overloaded operator
126+
* s >> x;
127+
* a & x;
128+
*/
129+
bool isLikelyStreamRead(bool cpp, const Token *op);
130+
124131
#endif // astutilsH

lib/checkuninitvar.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -885,15 +885,15 @@ void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, Alloc alloc
885885

886886
bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc alloc) const
887887
{
888-
if (alloc == NO_ALLOC && ((Token::Match(vartok->previous(), "return|delete") && vartok->strAt(1) != "=") || (vartok->strAt(-1) == "]" && vartok->linkAt(-1)->strAt(-1) == "delete")))
888+
if (alloc == NO_ALLOC && ((Token::Match(vartok->previous(), "return|delete %var% !!=")) || (vartok->strAt(-1) == "]" && vartok->linkAt(-1)->strAt(-1) == "delete")))
889889
return true;
890890

891891
// Passing variable to typeof/__alignof__
892892
if (Token::Match(vartok->tokAt(-3), "typeof|__alignof__ ( * %name%"))
893893
return false;
894894

895895
// Accessing Rvalue member using "." or "->"
896-
if (vartok->strAt(1) == "." && vartok->strAt(-1) != "&") {
896+
if (Token::Match(vartok->previous(), "!!& %var% .")) {
897897
// Is struct member passed to function?
898898
if (!pointer && Token::Match(vartok->previous(), "[,(] %name% . %name%")) {
899899
// TODO: there are FN currently:
@@ -939,20 +939,21 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
939939
if (_tokenizer->isCPP() && alloc == ARRAY && Token::Match(vartok->tokAt(-4), "& %var% =|( *"))
940940
return false;
941941

942-
if (_tokenizer->isCPP() && Token::Match(vartok->previous(), ">>|<<")) {
942+
if (isLikelyStreamRead(_tokenizer->isCPP(), vartok->previous()))
943+
return false;
944+
945+
if (_tokenizer->isCPP() && Token::Match(vartok->previous(), "<<")) {
943946
const Token* tok2 = vartok->previous();
944-
if (Token::simpleMatch(tok2->astOperand1(), ">>"))
945-
return false; // Looks like stream operator, initializes the variable
946-
if (Token::simpleMatch(tok2, "<<")) {
947-
// Looks like stream operator, but could also initialize the variable. Check lhs.
948-
do {
949-
tok2 = tok2->astOperand1();
950-
} while (Token::simpleMatch(tok2, "<<"));
951-
if (tok2 && tok2->strAt(-1) == "::")
952-
tok2 = tok2->previous();
953-
if (tok2 && (Token::simpleMatch(tok2->previous(), "std ::") || (tok2->variable() && tok2->variable()->isStlType()) || tok2->isStandardType() || tok2->isEnumType()))
954-
return true;
955-
}
947+
948+
// Looks like stream operator, but could also initialize the variable. Check lhs.
949+
do {
950+
tok2 = tok2->astOperand1();
951+
} while (Token::simpleMatch(tok2, "<<"));
952+
if (tok2 && tok2->strAt(-1) == "::")
953+
tok2 = tok2->previous();
954+
if (tok2 && (Token::simpleMatch(tok2->previous(), "std ::") || (tok2->variable() && tok2->variable()->isStlType()) || tok2->isStandardType() || tok2->isEnumType()))
955+
return true;
956+
956957
const Variable *var = vartok->tokAt(-2)->variable();
957958
return (var && (var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType()));
958959
}

lib/checkunusedvar.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
//---------------------------------------------------------------------------
2121
#include "checkunusedvar.h"
2222

23+
#include "astutils.h"
2324
#include "errorlogger.h"
2425
#include "settings.h"
2526
#include "symboldatabase.h"
@@ -1127,6 +1128,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
11271128
variables.use(tok->next()->varId(), tok); // use = read + write
11281129
} else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]")) {
11291130
variables.read(tok->varId(), tok);
1131+
} else if (isLikelyStreamRead(_tokenizer->isCPP(),tok->previous())) {
1132+
variables.use(tok->varId(), tok);
11301133
}
11311134

11321135
// function parameter

lib/valueflow.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,16 +2012,10 @@ static bool valueFlowForward(Token * const startToken,
20122012
}
20132013

20142014
// bailout: possible assignment using >>
2015-
if (Token::Match(tok2->previous(), ">> %name% >>|;")) {
2016-
const Token *parent = tok2->previous();
2017-
do {
2018-
parent = parent->astParent();
2019-
} while (Token::simpleMatch(parent, ">>"));
2020-
if (!parent) {
2021-
if (settings->debugwarnings)
2022-
bailout(tokenlist, errorLogger, tok2, "Possible assignment of " + tok2->str() + " using >>");
2023-
return false;
2024-
}
2015+
if (isLikelyStreamRead(tokenlist->isCPP(), tok2->previous())) {
2016+
if (settings->debugwarnings)
2017+
bailout(tokenlist, errorLogger, tok2, "Possible assignment of " + tok2->str() + " using " + tok2->strAt(-1));
2018+
return false;
20252019
}
20262020

20272021
// skip if variable is conditionally used in ?: expression

test/testuninitvar.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,18 @@ class TestUninitVar : public TestFixture {
473473
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
474474
}
475475

476+
// #8494 : Overloaded & operator
477+
checkUninitVar("void f() {\n"
478+
" int x;\n"
479+
" a & x;\n"
480+
"}");
481+
ASSERT_EQUALS("", errout.str());
482+
checkUninitVar("void f(int a) {\n"
483+
" int x;\n"
484+
" a & x;\n"
485+
"}");
486+
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: x\n", errout.str());
487+
476488
checkUninitVar("void a() {\n" // asm
477489
" int x;\n"
478490
" asm();\n"
@@ -1817,7 +1829,8 @@ class TestUninitVar : public TestFixture {
18171829
{
18181830
checkUninitVar("static int foo() {\n"
18191831
" int ret;\n"
1820-
" return cin >> ret;\n"
1832+
" cin >> ret;\n"
1833+
" return ret;\n"
18211834
"}");
18221835
ASSERT_EQUALS("", errout.str());
18231836

@@ -2183,9 +2196,8 @@ class TestUninitVar : public TestFixture {
21832196
{
21842197
const char code[] = "void f() {\n"
21852198
" int x;\n"
2186-
" if (i >> x) { }\n"
2199+
" i >> x;\n"
21872200
"}";
2188-
21892201
checkUninitVar(code, "test.cpp");
21902202
ASSERT_EQUALS("", errout.str());
21912203

test/testunusedvar.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,19 @@ class TestUnusedVar : public TestFixture {
17891789
"}");
17901790
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is not assigned a value.\n"
17911791
"[test.cpp:2]: (style) Variable 'y' is not assigned a value.\n", errout.str());
1792+
1793+
// ticket #8494
1794+
functionVariableUsage("void f(C c) {\n"
1795+
" int x;\n"
1796+
" c & x;\n"
1797+
"}");
1798+
ASSERT_EQUALS("", errout.str());
1799+
1800+
functionVariableUsage("void f(int c) {\n"
1801+
" int x;\n"
1802+
" c & x;\n"
1803+
"}");
1804+
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is not assigned a value.\n", errout.str());
17921805
}
17931806

17941807
void localvar33() { // ticket #2345

test/testvalueflow.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3067,6 +3067,14 @@ class TestValueFlow : public TestFixture {
30673067
"}\n";
30683068
values = tokenValues(code, "x +");
30693069
ASSERT_EQUALS(true, values.empty());
3070+
3071+
// #8494 - overloaded operator &
3072+
code = "void f() {\n"
3073+
" int x;\n"
3074+
" a & x;\n"
3075+
"}";
3076+
values = tokenValues(code, "x ; }");
3077+
ASSERT_EQUALS(true, values.empty());
30703078
}
30713079
};
30723080

0 commit comments

Comments
 (0)