Fixed #8494 (False positive: serialization class overloads operator)

This commit is contained in:
Daniel Marjamäki 2018-04-17 14:23:04 +02:00
parent 7d5a1b1248
commit c84628c28a
8 changed files with 89 additions and 28 deletions

View File

@ -625,3 +625,26 @@ const Token *findLambdaEndToken(const Token *first)
return tok->link();
return nullptr;
}
bool isLikelyStreamRead(bool cpp, const Token *op)
{
if (!cpp)
return false;
if (Token::Match(op, ">> %name% >>|;")) {
const Token *parent = op;
while (Token::simpleMatch(parent->astParent(), ">>"))
parent = parent->astParent();
if (parent->astParent())
return false;
if (!parent->astOperand1() || !parent->astOperand2())
return false;
return (!parent->astOperand1()->valueType() || !parent->astOperand1()->valueType()->isIntegral());
}
if (Token::Match(op, "& %name% ;") && !op->astParent() && op->astOperand1() && op->astOperand2() && (!op->astOperand1()->valueType() || !op->astOperand1()->valueType()->isIntegral()))
return true;
return false;
}

View File

@ -121,4 +121,11 @@ std::vector<const Token *> getArguments(const Token *ftok);
*/
const Token *findLambdaEndToken(const Token *first);
/**
* do we see a likely write of rhs through overloaded operator
* s >> x;
* a & x;
*/
bool isLikelyStreamRead(bool cpp, const Token *op);
#endif // astutilsH

View File

@ -885,7 +885,7 @@ void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, Alloc alloc
bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc alloc) const
{
if (alloc == NO_ALLOC && ((Token::Match(vartok->previous(), "return|delete") && vartok->strAt(1) != "=") || (vartok->strAt(-1) == "]" && vartok->linkAt(-1)->strAt(-1) == "delete")))
if (alloc == NO_ALLOC && ((Token::Match(vartok->previous(), "return|delete %var% !!=")) || (vartok->strAt(-1) == "]" && vartok->linkAt(-1)->strAt(-1) == "delete")))
return true;
// Passing variable to typeof/__alignof__
@ -893,7 +893,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
return false;
// Accessing Rvalue member using "." or "->"
if (vartok->strAt(1) == "." && vartok->strAt(-1) != "&") {
if (Token::Match(vartok->previous(), "!!& %var% .")) {
// Is struct member passed to function?
if (!pointer && Token::Match(vartok->previous(), "[,(] %name% . %name%")) {
// TODO: there are FN currently:
@ -939,20 +939,21 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
if (_tokenizer->isCPP() && alloc == ARRAY && Token::Match(vartok->tokAt(-4), "& %var% =|( *"))
return false;
if (_tokenizer->isCPP() && Token::Match(vartok->previous(), ">>|<<")) {
if (isLikelyStreamRead(_tokenizer->isCPP(), vartok->previous()))
return false;
if (_tokenizer->isCPP() && Token::Match(vartok->previous(), "<<")) {
const Token* tok2 = vartok->previous();
if (Token::simpleMatch(tok2->astOperand1(), ">>"))
return false; // Looks like stream operator, initializes the variable
if (Token::simpleMatch(tok2, "<<")) {
// Looks like stream operator, but could also initialize the variable. Check lhs.
do {
tok2 = tok2->astOperand1();
} while (Token::simpleMatch(tok2, "<<"));
if (tok2 && tok2->strAt(-1) == "::")
tok2 = tok2->previous();
if (tok2 && (Token::simpleMatch(tok2->previous(), "std ::") || (tok2->variable() && tok2->variable()->isStlType()) || tok2->isStandardType() || tok2->isEnumType()))
return true;
}
// Looks like stream operator, but could also initialize the variable. Check lhs.
do {
tok2 = tok2->astOperand1();
} while (Token::simpleMatch(tok2, "<<"));
if (tok2 && tok2->strAt(-1) == "::")
tok2 = tok2->previous();
if (tok2 && (Token::simpleMatch(tok2->previous(), "std ::") || (tok2->variable() && tok2->variable()->isStlType()) || tok2->isStandardType() || tok2->isEnumType()))
return true;
const Variable *var = vartok->tokAt(-2)->variable();
return (var && (var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType()));
}

View File

@ -20,6 +20,7 @@
//---------------------------------------------------------------------------
#include "checkunusedvar.h"
#include "astutils.h"
#include "errorlogger.h"
#include "settings.h"
#include "symboldatabase.h"
@ -1127,6 +1128,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
variables.use(tok->next()->varId(), tok); // use = read + write
} else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]")) {
variables.read(tok->varId(), tok);
} else if (isLikelyStreamRead(_tokenizer->isCPP(),tok->previous())) {
variables.use(tok->varId(), tok);
}
// function parameter

View File

@ -2012,16 +2012,10 @@ static bool valueFlowForward(Token * const startToken,
}
// bailout: possible assignment using >>
if (Token::Match(tok2->previous(), ">> %name% >>|;")) {
const Token *parent = tok2->previous();
do {
parent = parent->astParent();
} while (Token::simpleMatch(parent, ">>"));
if (!parent) {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "Possible assignment of " + tok2->str() + " using >>");
return false;
}
if (isLikelyStreamRead(tokenlist->isCPP(), tok2->previous())) {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "Possible assignment of " + tok2->str() + " using " + tok2->strAt(-1));
return false;
}
// skip if variable is conditionally used in ?: expression

View File

@ -473,6 +473,18 @@ private:
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
}
// #8494 : Overloaded & operator
checkUninitVar("void f() {\n"
" int x;\n"
" a & x;\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void f(int a) {\n"
" int x;\n"
" a & x;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: x\n", errout.str());
checkUninitVar("void a() {\n" // asm
" int x;\n"
" asm();\n"
@ -1817,7 +1829,8 @@ private:
{
checkUninitVar("static int foo() {\n"
" int ret;\n"
" return cin >> ret;\n"
" cin >> ret;\n"
" return ret;\n"
"}");
ASSERT_EQUALS("", errout.str());
@ -2183,9 +2196,8 @@ private:
{
const char code[] = "void f() {\n"
" int x;\n"
" if (i >> x) { }\n"
" i >> x;\n"
"}";
checkUninitVar(code, "test.cpp");
ASSERT_EQUALS("", errout.str());

View File

@ -1789,6 +1789,19 @@ private:
"}");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is not assigned a value.\n"
"[test.cpp:2]: (style) Variable 'y' is not assigned a value.\n", errout.str());
// ticket #8494
functionVariableUsage("void f(C c) {\n"
" int x;\n"
" c & x;\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void f(int c) {\n"
" int x;\n"
" c & x;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is not assigned a value.\n", errout.str());
}
void localvar33() { // ticket #2345

View File

@ -3067,6 +3067,14 @@ private:
"}\n";
values = tokenValues(code, "x +");
ASSERT_EQUALS(true, values.empty());
// #8494 - overloaded operator &
code = "void f() {\n"
" int x;\n"
" a & x;\n"
"}";
values = tokenValues(code, "x ; }");
ASSERT_EQUALS(true, values.empty());
}
};