Fixed #1174 (improve check: Unintialized variable not detected in subfunction)

This commit is contained in:
Daniel Marjamäki 2010-01-11 22:28:07 +01:00
parent c666a9662b
commit d3b7f5931f
3 changed files with 96 additions and 2 deletions

View File

@ -1118,6 +1118,7 @@ void CheckOther::nullPointer()
} }
/** /**
* \brief parse a function call and extract information about variable usage * \brief parse a function call and extract information about variable usage
* \param tok first token * \param tok first token
@ -1620,7 +1621,7 @@ private:
if (tok.varId()) if (tok.varId())
{ {
// Used.. // Used..
if (Token::Match(tok.previous(), "[[+-*/] %var% []+-*/]")) if (Token::Match(tok.previous(), "[[(,+-*/] %var% []),+-*/]"))
{ {
use(foundError, checks, &tok); use(foundError, checks, &tok);
return &tok; return &tok;
@ -1708,7 +1709,7 @@ private:
} }
} }
if (Token::Match(&tok, "%var% (")) if (Token::Match(&tok, "%var% (") && uvarFunctions.find(tok.str()) == uvarFunctions.end())
{ {
if (Token::simpleMatch(&tok, "sizeof (")) if (Token::simpleMatch(&tok, "sizeof ("))
return tok.next()->link(); return tok.next()->link();
@ -1891,8 +1892,61 @@ private:
return ExecutionPath::parseCondition(tok, checks); return ExecutionPath::parseCondition(tok, checks);
} }
public:
static std::set<std::string> uvarFunctions;
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func)
{
for (const Token *tok = tokens; tok; tok = tok->next())
{
if (tok->str() == "{")
{
tok = tok->link();
continue;
}
if (tok->str() != "::" && Token::Match(tok->next(), "%var% ( %type%"))
{
if (!Token::simpleMatch(tok->tokAt(2)->link(), ") {"))
continue;
const Token *tok2 = tok->tokAt(3);
while (tok2 && tok2->str() != ")")
{
if (tok2->str() == ",")
tok2 = tok2->next();
if (Token::Match(tok2, "%type% %var% ,|)") && tok2->isStandardType())
{
tok2 = tok2->tokAt(2);
continue;
}
if (Token::Match(tok2, "const %type% %var% ,|)") && tok2->next()->isStandardType())
{
tok2 = tok2->tokAt(2);
continue;
}
break;
}
// found simple function..
if (tok2->link() == tok->tokAt(2))
func.insert(tok->next()->str());
}
}
}
}; };
std::set<std::string> CheckUninitVar::uvarFunctions;
void CheckOther::analyseFunctions(const Token * const tokens, std::set<std::string> &func)
{
CheckUninitVar::analyseFunctions(tokens, func);
}
void CheckOther::executionPaths() void CheckOther::executionPaths()
@ -1905,6 +1959,7 @@ void CheckOther::executionPaths()
// check if variable is accessed uninitialized.. // check if variable is accessed uninitialized..
{ {
CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions);
CheckUninitVar c(this); CheckUninitVar c(this);
checkExecutionPaths(_tokenizer->tokens(), &c); checkExecutionPaths(_tokenizer->tokens(), &c);
} }

View File

@ -81,6 +81,11 @@ public:
checkOther.executionPaths(); checkOther.executionPaths();
} }
// TODO move CheckUninitVar?
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func);
// Casting // Casting
void warningOldStylePointerCast(); void warningOldStylePointerCast();

View File

@ -70,6 +70,7 @@ private:
TEST_CASE(nullpointer7); TEST_CASE(nullpointer7);
TEST_CASE(uninitvar1); TEST_CASE(uninitvar1);
TEST_CASE(uninitvar_func); // analyse functions
TEST_CASE(oldStylePointerCast); TEST_CASE(oldStylePointerCast);
@ -1668,6 +1669,39 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// sub functions..
checkUninitVar("int foo(int x) { return x; }\n"
"void f2()\n"
"{\n"
" int x;\n"
" foo(x);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: x\n", errout.str());
}
std::string analyseFunctions(const char code[])
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
std::set<std::string> f;
CheckOther::analyseFunctions(tokenizer.tokens(), f);
std::string ret;
for (std::set<std::string>::const_iterator it = f.begin(); it != f.end(); ++it)
ret += *it + " ";
return ret;
}
void uninitvar_func()
{
ASSERT_EQUALS("foo ", analyseFunctions("void foo(int x) { }"));
ASSERT_EQUALS("", analyseFunctions("void foo(s x) { }"));
} }