uninitialized variables: added check
This commit is contained in:
parent
4a61bd0432
commit
c6d7fad84f
|
@ -1160,6 +1160,131 @@ void CheckOther::nullPointer()
|
||||||
nullPointerConditionalAssignment();
|
nullPointerConditionalAssignment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const Token *uninitvar_checkscope(const Token *tok, const unsigned int varid, bool &init)
|
||||||
|
{
|
||||||
|
/* limit the checking in conditional code..
|
||||||
|
* int x;
|
||||||
|
* if (y)
|
||||||
|
* x = 33;
|
||||||
|
* if (y)
|
||||||
|
* return x;
|
||||||
|
*/
|
||||||
|
bool limit = false;
|
||||||
|
|
||||||
|
for (; tok; tok = tok->next())
|
||||||
|
{
|
||||||
|
if (tok->str() == "}")
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// todo: handle for/while
|
||||||
|
if (Token::Match(tok, "for|while"))
|
||||||
|
{
|
||||||
|
init = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok->str() == "if")
|
||||||
|
{
|
||||||
|
bool canInit = false;
|
||||||
|
bool ifInit = true;
|
||||||
|
while (tok->str() == "if")
|
||||||
|
{
|
||||||
|
// goto "("
|
||||||
|
tok = tok->next();
|
||||||
|
|
||||||
|
// goto ")"
|
||||||
|
tok = tok ? tok->link() : 0;
|
||||||
|
|
||||||
|
// goto "{"
|
||||||
|
tok = tok ? tok->next() : 0;
|
||||||
|
|
||||||
|
if (!Token::simpleMatch(tok, "{"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Recursively check into the if ..
|
||||||
|
bool init2 = false;
|
||||||
|
const Token *tokerr = uninitvar_checkscope(tok->next(), varid, init2);
|
||||||
|
if (!limit && tokerr)
|
||||||
|
return tokerr;
|
||||||
|
|
||||||
|
// if the scope didn't initialize then this whole if-chain is treated as non-initializing
|
||||||
|
ifInit &= init2;
|
||||||
|
canInit |= init2;
|
||||||
|
|
||||||
|
// goto "}"
|
||||||
|
tok = tok->link();
|
||||||
|
|
||||||
|
// there is no else => not initialized
|
||||||
|
if (Token::Match(tok, "} !!else"))
|
||||||
|
{
|
||||||
|
ifInit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse next "if"..
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
if (tok->str() == "if")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// there is no "if"..
|
||||||
|
init2 = false;
|
||||||
|
tokerr = uninitvar_checkscope(tok->next(), varid, init2);
|
||||||
|
if (!limit && tokerr)
|
||||||
|
return tokerr;
|
||||||
|
|
||||||
|
ifInit &= init2;
|
||||||
|
canInit |= init2;
|
||||||
|
|
||||||
|
tok = tok->link();
|
||||||
|
if (!tok)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifInit)
|
||||||
|
{
|
||||||
|
init = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canInit)
|
||||||
|
{
|
||||||
|
limit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(tok, "%varid% =", varid))
|
||||||
|
{
|
||||||
|
init = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(tok, "return| %varid% .|", varid))
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::uninitvar()
|
||||||
|
{
|
||||||
|
const Token *tok = _tokenizer->tokens();
|
||||||
|
while (0 != (tok = Token::findmatch(tok, "[{};] %type% *| %var% ;")))
|
||||||
|
{
|
||||||
|
// goto the variable
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
if (tok->str() == "*")
|
||||||
|
tok = tok->next();
|
||||||
|
|
||||||
|
// check that the variable id is non-zero
|
||||||
|
if (tok->varId() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool init = false;
|
||||||
|
const Token *tokerr = uninitvar_checkscope(tok->next(), tok->varId(), init);
|
||||||
|
if (tokerr)
|
||||||
|
uninitvarError(tokerr, tok->str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CheckOther::checkZeroDivision()
|
void CheckOther::checkZeroDivision()
|
||||||
{
|
{
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
|
@ -1301,6 +1426,11 @@ void CheckOther::nullPointerError(const Token *tok, const std::string &varname,
|
||||||
reportError(tok, Severity::error, "nullPointer", "Possible null pointer dereference: " + varname + " - otherwise it is redundant to check if " + varname + " is null at line " + MathLib::toString<long>(line));
|
reportError(tok, Severity::error, "nullPointer", "Possible null pointer dereference: " + varname + " - otherwise it is redundant to check if " + varname + " is null at line " + MathLib::toString<long>(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::uninitvarError(const Token *tok, const std::string &varname)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::error, "uninitvar", "Uninitialized variable: " + varname);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckOther::zerodivError(const Token *tok)
|
void CheckOther::zerodivError(const Token *tok)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "zerodiv", "Division by zero");
|
reportError(tok, Severity::error, "zerodiv", "Division by zero");
|
||||||
|
|
|
@ -76,6 +76,7 @@ public:
|
||||||
checkOther.strPlusChar();
|
checkOther.strPlusChar();
|
||||||
checkOther.invalidFunctionUsage();
|
checkOther.invalidFunctionUsage();
|
||||||
checkOther.checkZeroDivision();
|
checkOther.checkZeroDivision();
|
||||||
|
checkOther.uninitvar();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Casting
|
// Casting
|
||||||
|
@ -111,6 +112,9 @@ public:
|
||||||
/** possible null pointer dereference */
|
/** possible null pointer dereference */
|
||||||
void nullPointer();
|
void nullPointer();
|
||||||
|
|
||||||
|
/** reading uninitialized var */
|
||||||
|
void uninitvar();
|
||||||
|
|
||||||
/** Check zero division*/
|
/** Check zero division*/
|
||||||
void checkZeroDivision();
|
void checkZeroDivision();
|
||||||
|
|
||||||
|
@ -124,6 +128,7 @@ public:
|
||||||
// haystack.remove(needle);
|
// haystack.remove(needle);
|
||||||
void redundantCondition2();
|
void redundantCondition2();
|
||||||
|
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
void redundantIfDelete0Error(const Token *tok);
|
void redundantIfDelete0Error(const Token *tok);
|
||||||
|
@ -142,6 +147,7 @@ public:
|
||||||
void strPlusChar(const Token *tok);
|
void strPlusChar(const Token *tok);
|
||||||
void nullPointerError(const Token *tok, const std::string &varname);
|
void nullPointerError(const Token *tok, const std::string &varname);
|
||||||
void nullPointerError(const Token *tok, const std::string &varname, const int line);
|
void nullPointerError(const Token *tok, const std::string &varname, const int line);
|
||||||
|
void uninitvarError(const Token *tok, const std::string &varname);
|
||||||
void zerodivError(const Token *tok);
|
void zerodivError(const Token *tok);
|
||||||
void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement);
|
void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement);
|
||||||
|
|
||||||
|
@ -151,6 +157,7 @@ public:
|
||||||
sprintfOverlappingDataError(0, "varname");
|
sprintfOverlappingDataError(0, "varname");
|
||||||
udivError(0);
|
udivError(0);
|
||||||
nullPointerError(0, "pointer");
|
nullPointerError(0, "pointer");
|
||||||
|
uninitvarError(0, "varname");
|
||||||
zerodivError(0);
|
zerodivError(0);
|
||||||
|
|
||||||
// style
|
// style
|
||||||
|
@ -186,7 +193,7 @@ public:
|
||||||
" * division with zero\n"
|
" * division with zero\n"
|
||||||
" * null pointer dereferencing\n"
|
" * null pointer dereferencing\n"
|
||||||
|
|
||||||
// warning
|
// style
|
||||||
" * C-style pointer cast in cpp file\n"
|
" * C-style pointer cast in cpp file\n"
|
||||||
" * redundant if\n"
|
" * redundant if\n"
|
||||||
" * bad usage of the function 'strtol'\n"
|
" * bad usage of the function 'strtol'\n"
|
||||||
|
@ -198,6 +205,7 @@ public:
|
||||||
" * variable scope can be limited\n"
|
" * variable scope can be limited\n"
|
||||||
" * condition that is always true/false\n"
|
" * condition that is always true/false\n"
|
||||||
" * unusal pointer arithmetic. For example: \"abc\" + 'd'\n"
|
" * unusal pointer arithmetic. For example: \"abc\" + 'd'\n"
|
||||||
|
" * uninitialized variables\n"
|
||||||
|
|
||||||
// optimisations
|
// optimisations
|
||||||
" * optimisation: detect post increment/decrement\n";
|
" * optimisation: detect post increment/decrement\n";
|
||||||
|
|
|
@ -68,6 +68,8 @@ private:
|
||||||
TEST_CASE(nullpointer5); // References should not be checked
|
TEST_CASE(nullpointer5); // References should not be checked
|
||||||
TEST_CASE(nullpointer6);
|
TEST_CASE(nullpointer6);
|
||||||
|
|
||||||
|
TEST_CASE(uninitvar1);
|
||||||
|
|
||||||
TEST_CASE(oldStylePointerCast);
|
TEST_CASE(oldStylePointerCast);
|
||||||
|
|
||||||
TEST_CASE(postIncrementDecrementStl);
|
TEST_CASE(postIncrementDecrementStl);
|
||||||
|
@ -910,6 +912,59 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void checkUninitVar(const char code[])
|
||||||
|
{
|
||||||
|
// Tokenize..
|
||||||
|
Tokenizer tokenizer;
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
|
// Clear the error buffer..
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
// Check for redundant code..
|
||||||
|
Settings settings;
|
||||||
|
settings._checkCodingStyle = true;
|
||||||
|
CheckOther checkOther(&tokenizer, &settings, this);
|
||||||
|
checkOther.uninitvar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninitvar1()
|
||||||
|
{
|
||||||
|
checkUninitVar("static void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" Foo *p;\n"
|
||||||
|
" if (x)\n"
|
||||||
|
" p = new Foo;\n"
|
||||||
|
" p->abcd();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: p\n", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar("int foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i;\n"
|
||||||
|
" if (x)\n"
|
||||||
|
" i = 22;\n"
|
||||||
|
" else\n"
|
||||||
|
" i = 33;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar("static void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" Foo *p;\n"
|
||||||
|
" if (x)\n"
|
||||||
|
" p = new Foo;\n"
|
||||||
|
" if (x)\n"
|
||||||
|
" p->abcd();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void checkOldStylePointerCast(const char code[])
|
void checkOldStylePointerCast(const char code[])
|
||||||
{
|
{
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
|
|
Loading…
Reference in New Issue