Refactoring the uninitialized variable / null pointer checks so they use a common function to inspect function calls
This commit is contained in:
parent
a7d48f2eb4
commit
ea51c3e098
|
@ -1118,6 +1118,68 @@ void CheckOther::nullPointer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief parse a function call and extract information about variable usage
|
||||||
|
* \param tok first token
|
||||||
|
* \param var variables that the function read / write.
|
||||||
|
* \param value 0 => invalid with null pointers as parameter.
|
||||||
|
* 1-.. => invalid with uninitialized data.
|
||||||
|
*/
|
||||||
|
static void parseFunctionCall(const Token &tok, std::list<const Token *> &var, unsigned char value)
|
||||||
|
{
|
||||||
|
// standard functions that dereference first parameter..
|
||||||
|
// both uninitialized data and null pointers are invalid.
|
||||||
|
static std::set<std::string> functionNames1;
|
||||||
|
if (functionNames1.empty())
|
||||||
|
{
|
||||||
|
functionNames1.insert("memchr");
|
||||||
|
functionNames1.insert("memcmp");
|
||||||
|
functionNames1.insert("strcat");
|
||||||
|
functionNames1.insert("strncat");
|
||||||
|
functionNames1.insert("strchr");
|
||||||
|
functionNames1.insert("strrchr");
|
||||||
|
functionNames1.insert("strcmp");
|
||||||
|
functionNames1.insert("strncmp");
|
||||||
|
functionNames1.insert("strdup");
|
||||||
|
functionNames1.insert("strlen");
|
||||||
|
functionNames1.insert("strstr");
|
||||||
|
}
|
||||||
|
|
||||||
|
// standard functions that dereference second parameter..
|
||||||
|
// both uninitialized data and null pointers are invalid.
|
||||||
|
static std::set<std::string> functionNames2;
|
||||||
|
if (functionNames2.empty())
|
||||||
|
{
|
||||||
|
functionNames2.insert("memcmp");
|
||||||
|
functionNames2.insert("memcpy");
|
||||||
|
functionNames2.insert("memmove");
|
||||||
|
functionNames2.insert("strcat");
|
||||||
|
functionNames2.insert("strncat");
|
||||||
|
functionNames2.insert("strcmp");
|
||||||
|
functionNames2.insert("strncmp");
|
||||||
|
functionNames2.insert("strcpy");
|
||||||
|
functionNames2.insert("strncpy");
|
||||||
|
functionNames2.insert("strstr");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1st parameter..
|
||||||
|
if (Token::Match(&tok, "%var% ( %var% ,|)") && tok.tokAt(2)->varId() > 0)
|
||||||
|
{
|
||||||
|
if (functionNames1.find(tok.str()) != functionNames1.end())
|
||||||
|
var.push_back(tok.tokAt(2));
|
||||||
|
else if (value == 0 && Token::Match(&tok, "memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf"))
|
||||||
|
var.push_back(tok.tokAt(2));
|
||||||
|
else if (Token::Match(&tok, "free|kfree|fclose|fflush"))
|
||||||
|
var.push_back(tok.tokAt(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2nd parameter..
|
||||||
|
if (Token::Match(&tok, "%var% ( %any% , %var% ,|)") && tok.tokAt(4)->varId() > 0)
|
||||||
|
{
|
||||||
|
if (functionNames2.find(tok.str()) != functionNames2.end())
|
||||||
|
var.push_back(tok.tokAt(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class CheckNullpointer : public ExecutionPath
|
class CheckNullpointer : public ExecutionPath
|
||||||
|
@ -1190,6 +1252,15 @@ private:
|
||||||
return vartok->next();
|
return vartok->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Token::Match(tok.previous(), "[;{}] %var% ("))
|
||||||
|
{
|
||||||
|
// parse usage..
|
||||||
|
std::list<const Token *> var;
|
||||||
|
parseFunctionCall(tok, var, 0);
|
||||||
|
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
|
||||||
|
dereference(foundError, checks, *it);
|
||||||
|
}
|
||||||
|
|
||||||
if (tok.varId() != 0)
|
if (tok.varId() != 0)
|
||||||
{
|
{
|
||||||
if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;"))
|
if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;"))
|
||||||
|
@ -1397,17 +1468,12 @@ private:
|
||||||
|
|
||||||
if (Token::Match(&tok, "%var% ("))
|
if (Token::Match(&tok, "%var% ("))
|
||||||
{
|
{
|
||||||
// reading 1st parameter..
|
// parse usage..
|
||||||
if (Token::Match(&tok, "strcat|strncat|strchr|strrchr|strstr|strlen|strdup ( %var%"))
|
|
||||||
{
|
{
|
||||||
use_array(foundError, checks, tok.tokAt(2));
|
std::list<const Token *> var;
|
||||||
}
|
parseFunctionCall(tok, var, 1);
|
||||||
|
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
|
||||||
// reading 2nd parameter..
|
use_array(foundError, checks, *it);
|
||||||
if (Token::Match(&tok, "strcpy|strstr ( %any% , %var% ) ") ||
|
|
||||||
Token::Match(&tok, "strncpy ( %any% , %var% ,"))
|
|
||||||
{
|
|
||||||
use_array(foundError, checks, tok.tokAt(4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// strncpy doesn't 0-terminate first parameter
|
// strncpy doesn't 0-terminate first parameter
|
||||||
|
|
|
@ -1211,6 +1211,13 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar("void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" FILE *f;\n"
|
||||||
|
" fflush(f);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("error", errout.str());
|
||||||
|
|
||||||
// arrays..
|
// arrays..
|
||||||
checkUninitVar("void f()\n"
|
checkUninitVar("void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
|
Loading…
Reference in New Issue