UninitVar: Fix false positives when there is possible cast

This commit is contained in:
Daniel Marjamäki 2019-02-26 19:26:46 +01:00
parent 13b37631a6
commit 9e93e89a4d
2 changed files with 43 additions and 5 deletions

View File

@ -54,6 +54,30 @@ static const struct CWE CWE676(676U);
static const struct CWE CWE908(908U); static const struct CWE CWE908(908U);
static const struct CWE CWE825(825U); static const struct CWE CWE825(825U);
// get ast parent, skip possible address-of and casts
static const Token *getAstParentSkipPossibleCastAndAddressOf(const Token *vartok, bool *unknown)
{
if (unknown)
*unknown = false;
if (!vartok)
return nullptr;
const Token *parent = vartok->astParent();
while (Token::Match(parent, ".|::"))
parent = parent->astParent();
if (!parent)
return nullptr;
if (parent->isUnaryOp("&"))
parent = parent->astParent();
else if (parent->str() == "&" && vartok == parent->astOperand2() && Token::Match(parent->astOperand1()->previous(), "( %type% )")) {
parent = parent->astParent();
if (unknown)
*unknown = true;
}
while (parent && parent->isCast())
parent = parent->astParent();
return parent;
}
void CheckUninitVar::check() void CheckUninitVar::check()
{ {
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@ -935,10 +959,16 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
} }
// Passing variable to function.. // Passing variable to function..
if (Token::Match(vartok->previous(), "[(,] %name% [,)]") || Token::Match(vartok->tokAt(-2), "[(,] & %name% [,)]")) { {
const int use = isFunctionParUsage(vartok, pointer, alloc); bool unknown = false;
if (use >= 0) const Token *possibleParent = getAstParentSkipPossibleCastAndAddressOf(vartok, &unknown);
return (use>0); if (Token::Match(possibleParent, "[(,]")) {
if (unknown)
return false; // TODO: output some info message?
const int use = isFunctionParUsage(vartok, pointer, alloc);
if (use >= 0)
return (use>0);
}
} }
if (Token::Match(vartok->previous(), "++|--|%cop%")) { if (Token::Match(vartok->previous(), "++|--|%cop%")) {
@ -1051,7 +1081,9 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
*/ */
int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc alloc) const int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc alloc) const
{ {
if (!Token::Match(vartok->previous(), "[(,]") && !Token::Match(vartok->tokAt(-2), "[(,] &")) bool unknown = false;
const Token *parent = getAstParentSkipPossibleCastAndAddressOf(vartok, &unknown);
if (unknown || !Token::Match(parent, "[(,]"))
return -1; return -1;
// locate start parentheses in function call.. // locate start parentheses in function call..

View File

@ -2571,6 +2571,12 @@ private:
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
checkUninitVar("int main() {\n"
" int done;\n"
" dostuff(1, (AuPointer) &done);\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void f() {\n" // #4778 - cast address of uninitialized variable checkUninitVar("void f() {\n" // #4778 - cast address of uninitialized variable
" long a;\n" " long a;\n"
" &a;\n" " &a;\n"