From 9e93e89a4d961cbd1ca4fc8599fe6f6b9a3000ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 26 Feb 2019 19:26:46 +0100 Subject: [PATCH] UninitVar: Fix false positives when there is possible cast --- lib/checkuninitvar.cpp | 42 +++++++++++++++++++++++++++++++++++++----- test/testuninitvar.cpp | 6 ++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index c9c0d750b..c17bf3201 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -54,6 +54,30 @@ static const struct CWE CWE676(676U); static const struct CWE CWE908(908U); 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() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -935,10 +959,16 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al } // Passing variable to function.. - if (Token::Match(vartok->previous(), "[(,] %name% [,)]") || Token::Match(vartok->tokAt(-2), "[(,] & %name% [,)]")) { - const int use = isFunctionParUsage(vartok, pointer, alloc); - if (use >= 0) - return (use>0); + { + bool unknown = false; + const Token *possibleParent = getAstParentSkipPossibleCastAndAddressOf(vartok, &unknown); + 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%")) { @@ -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 { - 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; // locate start parentheses in function call.. diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 1ef08d12a..c45d95cf7 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -2571,6 +2571,12 @@ private: "}"); 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 " long a;\n" " &a;\n"