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())
|
for (; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
if (tok->str() == "}")
|
if (tok->str() == "}" || tok->str() == "break")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "while ("))
|
if (Token::simpleMatch(tok, "while ("))
|
||||||
|
@ -122,6 +122,82 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
|
||||||
return;
|
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
|
// for/while/switch/do .. bail out
|
||||||
if (Token::Match(tok, "for|while|switch|do"))
|
if (Token::Match(tok, "for|while|switch|do"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -75,7 +75,8 @@ private:
|
||||||
TEST_CASE(uninitvar_arrays); // arrays
|
TEST_CASE(uninitvar_arrays); // arrays
|
||||||
TEST_CASE(uninitvar_class); // class/struct
|
TEST_CASE(uninitvar_class); // class/struct
|
||||||
TEST_CASE(uninitvar_enum); // enum variables
|
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_references); // references
|
||||||
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate
|
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate
|
||||||
TEST_CASE(uninitvar_func); // analyse functions
|
TEST_CASE(uninitvar_func); // analyse functions
|
||||||
|
@ -1659,44 +1660,6 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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..
|
// while..
|
||||||
checkUninitVar("int f()\n"
|
checkUninitVar("int f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -1741,6 +1704,58 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
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..
|
// arrays..
|
||||||
void uninitvar_arrays()
|
void uninitvar_arrays()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue