Fixed #1721 (False negative: uninitialized variable in switch block)

This commit is contained in:
Daniel Marjamäki 2010-06-03 20:02:58 +02:00
parent 90a3d29d70
commit b11e23eb08
2 changed files with 131 additions and 40 deletions

View File

@ -89,7 +89,7 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
for (; tok; tok = tok->next())
{
if (tok->str() == "}")
if (tok->str() == "}" || tok->str() == "break")
return;
if (Token::simpleMatch(tok, "while ("))
@ -122,6 +122,82 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
return;
}
if (tok->str() == "switch")
{
const Token *tok2 = tok->next()->link();
if (Token::simpleMatch(tok2, ") { case"))
{
// what variable ids should the if be counted for?
std::set<unsigned int> countif;
std::list<ExecutionPath *> newchecks;
for (tok2 = tok2->tokAt(2); tok2; tok2 = tok2->next())
{
if (tok2->str() == "{")
tok2 = tok2->link();
else if (tok2->str() == "}")
break;
else if (tok2->str() == "case")
{
if (Token::Match(tok2, "case %num% : ; case"))
continue;
std::set<unsigned int> countif2;
std::list<ExecutionPath *> c;
if (!checks.empty())
{
std::list<ExecutionPath *>::const_iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
{
c.push_back((*it)->copy());
if ((*it)->varId != 0)
countif2.insert((*it)->varId);
}
}
checkExecutionPaths_(tok2, c);
while (!c.empty())
{
if (c.back()->varId == 0)
{
c.pop_back();
continue;
}
bool duplicate = false;
std::list<ExecutionPath *>::const_iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
{
if (*(*it) == *c.back())
{
duplicate = true;
countif2.erase((*it)->varId);
break;
}
}
if (!duplicate)
newchecks.push_back(c.back());
c.pop_back();
}
// Add countif2 ids to countif.. countif.
countif.insert(countif2.begin(), countif2.end());
}
// Add newchecks to checks..
std::copy(newchecks.begin(), newchecks.end(), std::back_inserter(checks));
// Increase numberOfIf
std::list<ExecutionPath *>::iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
{
if (countif.find((*it)->varId) != countif.end())
(*it)->numberOfIf++;
}
}
}
}
// for/while/switch/do .. bail out
if (Token::Match(tok, "for|while|switch|do"))
{

View File

@ -75,7 +75,8 @@ private:
TEST_CASE(uninitvar_arrays); // arrays
TEST_CASE(uninitvar_class); // class/struct
TEST_CASE(uninitvar_enum); // enum variables
TEST_CASE(uninitvar_if); // handling if/while/switch
TEST_CASE(uninitvar_if); // handling if/while
TEST_CASE(uninitvar_switch); // handling switch
TEST_CASE(uninitvar_references); // references
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate
TEST_CASE(uninitvar_func); // analyse functions
@ -1659,44 +1660,6 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
// switch..
checkUninitVar("char * f()\n"
"{\n"
" static char ret[200];\n"
" memset(ret, 0, sizeof(ret));\n"
" switch (x)\n"
" {\n"
" case 1: return ret;\n"
" case 2: return ret;\n"
" }\n"
" return 0;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
checkUninitVar("int foo(const int iVar, unsigned int slot, unsigned int pin)\n"
"{\n"
" int i;\n"
"\n"
" if (iVar == 0)\n"
" {\n"
" switch (slot)\n"
" {\n"
" case 4: return 5;\n"
" default: return -1;\n"
" }\n"
" }\n"
" else\n"
" {\n"
" switch (pin)\n"
" {\n"
" case 0: i = 2; break;\n"
" default: i = -1; break;\n"
" }\n"
" }\n"
" return i;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// while..
checkUninitVar("int f()\n"
"{\n"
@ -1741,6 +1704,58 @@ private:
ASSERT_EQUALS("", errout.str());
}
// switch..
void uninitvar_switch()
{
checkUninitVar("void f(int x)\n"
"{\n"
" short c;\n"
" switch(x) {\n"
" case 1:\n"
" c++;\n"
" break;\n"
" };\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: c\n", errout.str());
checkUninitVar("char * f()\n"
"{\n"
" static char ret[200];\n"
" memset(ret, 0, sizeof(ret));\n"
" switch (x)\n"
" {\n"
" case 1: return ret;\n"
" case 2: return ret;\n"
" }\n"
" return 0;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
checkUninitVar("int foo(const int iVar, unsigned int slot, unsigned int pin)\n"
"{\n"
" int i;\n"
"\n"
" if (iVar == 0)\n"
" {\n"
" switch (slot)\n"
" {\n"
" case 4: return 5;\n"
" default: return -1;\n"
" }\n"
" }\n"
" else\n"
" {\n"
" switch (pin)\n"
" {\n"
" case 0: i = 2; break;\n"
" default: i = -1; break;\n"
" }\n"
" }\n"
" return i;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
// arrays..
void uninitvar_arrays()
{