Fixed #1721 (False negative: uninitialized variable in switch block)
This commit is contained in:
parent
90a3d29d70
commit
b11e23eb08
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue