Fixed #5207 (Struct uninitialized members useage is not giving error (malloc).)

This commit is contained in:
Daniel Marjamäki 2013-12-04 20:32:20 +01:00
parent 663f5a14b0
commit 14a00046a3
3 changed files with 126 additions and 41 deletions

View File

@ -1088,9 +1088,11 @@ void CheckUninitVar::checkScope(const Scope* scope)
tok = tok->next();
if (Token::findsimplematch(i->typeStartToken(), "=", tok))
continue;
if (stdtype || i->isPointer())
checkScopeForVariable(scope, tok, *i, NULL, NULL, "");
if (Token::Match(i->typeStartToken(), "struct %type% %var% ;")) {
if (stdtype || i->isPointer()) {
bool alloc = false;
checkScopeForVariable(scope, tok, *i, NULL, NULL, &alloc, "");
}
if (Token::Match(i->typeStartToken(), "struct %type% *| %var% ;")) {
const std::string structname(i->typeStartToken()->next()->str());
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
@ -1113,8 +1115,10 @@ void CheckUninitVar::checkScope(const Scope* scope)
}
}
if (!innerunion)
checkScopeForVariable(scope, tok, *i, NULL, NULL, var.name());
if (!innerunion) {
bool alloc = false;
checkScopeForVariable(scope, tok, *i, NULL, NULL, &alloc, var.name());
}
}
}
}
@ -1164,7 +1168,7 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<unsigned
}
}
bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, const std::string &membervar)
bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, bool * const alloc, const std::string &membervar)
{
const bool suppressErrors(possibleInit && *possibleInit);
@ -1173,6 +1177,9 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
unsigned int number_of_if = 0;
if (var.declarationId() == 0U)
return true;
// variable values
std::map<unsigned int, int> variableValue;
static const int NOT_ZERO = (1<<30); // special variable value
@ -1195,7 +1202,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
// Unconditional inner scope..
if (tok->str() == "{" && Token::Match(tok->previous(), "[;{}]")) {
if (checkScopeForVariable(scope, tok->next(), var, possibleInit, NULL, membervar))
if (checkScopeForVariable(scope, tok->next(), var, possibleInit, NULL, alloc, membervar))
return true;
tok = tok->link();
continue;
@ -1213,7 +1220,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
conditionAlwaysTrueOrFalse(tok, variableValue, &alwaysTrue, &alwaysFalse);
// initialization / usage in condition..
if (!alwaysTrue && checkIfForWhileHead(tok->next(), var, suppressErrors, bool(number_of_if == 0), membervar))
if (!alwaysTrue && checkIfForWhileHead(tok->next(), var, suppressErrors, bool(number_of_if == 0), alloc && *alloc, membervar))
return true;
// checking if a not-zero variable is zero => bail out
@ -1236,7 +1243,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
if (tok->str() == "{") {
bool possibleInitIf(number_of_if > 0 || suppressErrors);
bool noreturnIf = false;
const bool initif = !alwaysFalse && checkScopeForVariable(scope, tok->next(), var, &possibleInitIf, &noreturnIf, membervar);
const bool initif = !alwaysFalse && checkScopeForVariable(scope, tok->next(), var, &possibleInitIf, &noreturnIf, alloc, membervar);
// bail out for such code:
// if (a) x=0; // conditional initialization
@ -1286,7 +1293,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
bool possibleInitElse(number_of_if > 0 || suppressErrors);
bool noreturnElse = false;
const bool initelse = !alwaysTrue && checkScopeForVariable(scope, tok->next(), var, &possibleInitElse, NULL, membervar);
const bool initelse = !alwaysTrue && checkScopeForVariable(scope, tok->next(), var, &possibleInitElse, NULL, alloc, membervar);
std::map<unsigned int, int> varValueElse;
if (!alwaysTrue && !initelse && !noreturnElse) {
@ -1340,14 +1347,14 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
const bool forwhile = Token::Match(tok, "for|while (");
// is variable initialized in for-head (don't report errors yet)?
if (forwhile && checkIfForWhileHead(tok->next(), var, true, false, membervar))
if (forwhile && checkIfForWhileHead(tok->next(), var, true, false, alloc && *alloc, membervar))
return true;
// goto the {
const Token *tok2 = forwhile ? tok->next()->link()->next() : tok->next();
if (tok2 && tok2->str() == "{") {
bool init = checkLoopBody(tok2, var, membervar, (number_of_if > 0) | suppressErrors);
bool init = checkLoopBody(tok2, var, alloc && *alloc, membervar, (number_of_if > 0) | suppressErrors);
// variable is initialized in the loop..
if (init)
@ -1356,7 +1363,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
// is variable used in for-head?
if (!suppressErrors) {
const Token *startCond = forwhile ? tok->next() : tok->next()->link()->tokAt(2);
checkIfForWhileHead(startCond, var, false, bool(number_of_if == 0), membervar);
checkIfForWhileHead(startCond, var, false, bool(number_of_if == 0), alloc && *alloc, membervar);
}
// goto "}"
@ -1406,8 +1413,12 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
}
// Use variable
else if (!suppressErrors && isVariableUsage(tok, var.isPointer(), _tokenizer->isCPP()))
else if (!suppressErrors && isVariableUsage(tok, var.isPointer(), alloc && *alloc, _tokenizer->isCPP())) {
if (alloc && *alloc)
uninitdataError(tok, tok->str());
else
uninitvarError(tok, tok->str());
}
else
// assume that variable is assigned
@ -1431,13 +1442,24 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
// variable is seen..
if (tok->varId() == var.declarationId()) {
// calling function that returns uninit data through pointer..
if (var.isPointer() &&
Token::Match(tok->next(), "= %var% (") &&
Token::simpleMatch(tok->linkAt(3), ") ;") &&
_settings->library.returnuninitdata.count(tok->strAt(2)) > 0U) {
if (alloc)
*alloc = true;
continue;
}
if (!membervar.empty()) {
if (isMemberVariableAssignment(tok, membervar)) {
checkRhs(tok, var, membervar);
checkRhs(tok, var, alloc && *alloc, membervar);
return true;
}
if (isMemberVariableUsage(tok, var.isPointer(), membervar))
if (isMemberVariableUsage(tok, var.isPointer(), alloc && *alloc, membervar))
uninitStructMemberError(tok, tok->str() + "." + membervar);
else if (Token::Match(tok->previous(), "[(,] %var% [,)]"))
@ -1445,12 +1467,16 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
} else {
// Use variable
if (!suppressErrors && isVariableUsage(tok, var.isPointer(), _tokenizer->isCPP()))
if (!suppressErrors && isVariableUsage(tok, var.isPointer(), alloc && *alloc, _tokenizer->isCPP())) {
if (alloc && *alloc)
uninitdataError(tok, tok->str());
else
uninitvarError(tok, tok->str());
}
else {
if (tok->strAt(1) == "=")
checkRhs(tok, var, "");
checkRhs(tok, var, alloc && *alloc, "");
// assume that variable is assigned
return true;
@ -1462,7 +1488,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
return false;
}
bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, const std::string &membervar)
bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, bool alloc, const std::string &membervar)
{
const Token * const endpar = startparentheses->link();
for (const Token *tok = startparentheses->next(); tok && tok != endpar; tok = tok->next()) {
@ -1472,13 +1498,13 @@ bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Va
if (isMemberVariableAssignment(tok, membervar))
return true;
if (isMemberVariableUsage(tok, var.isPointer(), membervar))
if (!suppressErrors && isMemberVariableUsage(tok, var.isPointer(), alloc, membervar))
uninitStructMemberError(tok, tok->str() + "." + membervar);
}
continue;
}
if (isVariableUsage(tok, var.isPointer(), _tokenizer->isCPP())) {
if (isVariableUsage(tok, var.isPointer(), alloc, _tokenizer->isCPP())) {
if (!suppressErrors)
uninitvarError(tok, tok->str());
else
@ -1488,13 +1514,13 @@ bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Va
}
if (Token::Match(tok, "sizeof|decltype|offsetof ("))
tok = tok->next()->link();
if (!isuninit && tok->str() == "&&")
if ((!isuninit || !membervar.empty()) && tok->str() == "&&")
suppressErrors = true;
}
return false;
}
bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const std::string &membervar, const bool suppressErrors)
bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const bool alloc, const std::string &membervar, const bool suppressErrors)
{
const Token *usetok = NULL;
@ -1511,7 +1537,7 @@ bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const
rhs = true;
if (tok2->str() == ";")
break;
if (rhs && tok2->varId() == var.declarationId() && isMemberVariableUsage(tok2, var.isPointer(), membervar)) {
if (rhs && tok2->varId() == var.declarationId() && isMemberVariableUsage(tok2, var.isPointer(), alloc, membervar)) {
assign = false;
break;
}
@ -1520,12 +1546,15 @@ bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const
return true;
}
if (isMemberVariableUsage(tok, var.isPointer(), membervar))
if (Token::Match(tok, "%var% ="))
return true;
if (isMemberVariableUsage(tok, var.isPointer(), alloc, membervar))
usetok = tok;
else if (Token::Match(tok->previous(), "[(,] %var% [,)]"))
return true;
} else {
if (isVariableUsage(tok, var.isPointer(), _tokenizer->isCPP()))
if (isVariableUsage(tok, var.isPointer(), alloc, _tokenizer->isCPP()))
usetok = tok;
else {
bool assign = true;
@ -1568,7 +1597,7 @@ bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const
return false;
}
void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, const std::string &membervar)
void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, bool alloc, const std::string &membervar)
{
bool rhs = false;
unsigned int indent = 0;
@ -1576,9 +1605,9 @@ void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, const std::
if (tok->str() == "=")
rhs = true;
else if (rhs && tok->varId() == var.declarationId()) {
if (membervar.empty() && isVariableUsage(tok, var.isPointer(), _tokenizer->isCPP()))
if (membervar.empty() && isVariableUsage(tok, var.isPointer(), alloc, _tokenizer->isCPP()))
uninitvarError(tok, tok->str());
else if (!membervar.empty() && isMemberVariableUsage(tok, var.isPointer(), membervar))
else if (!membervar.empty() && isMemberVariableUsage(tok, var.isPointer(), alloc, membervar))
uninitStructMemberError(tok, tok->str() + "." + membervar);
} else if (tok->str() == ";" || (indent==0 && tok->str() == ","))
@ -1594,9 +1623,9 @@ void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, const std::
}
}
bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, bool cpp)
bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, bool alloc, bool cpp)
{
if (vartok->previous()->str() == "return")
if (vartok->previous()->str() == "return" && !alloc)
return true;
// Passing variable to typeof/__alignof__
@ -1707,6 +1736,10 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, bool cpp
bool unknown = false;
if (pointer && CheckNullPointer::isPointerDeRef(vartok, unknown)) {
// pointer is allocated
if (alloc)
return false;
// function parameter?
bool functionParameter = false;
if (Token::Match(vartok->tokAt(-2), "%var% (") || vartok->previous()->str() == ",")
@ -1760,14 +1793,14 @@ bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::str
return false;
}
bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, const std::string &membervar) const
bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, bool alloc, const std::string &membervar) const
{
if (isMemberVariableAssignment(tok, membervar))
return false;
if (Token::Match(tok, "%var% . %var%") && tok->strAt(2) == membervar)
return true;
else if (Token::Match(tok->previous(), "[(,] %var% [,)]") && isVariableUsage(tok, isPointer, _tokenizer->isCPP()))
else if (Token::Match(tok->previous(), "[(,] %var% [,)]") && isVariableUsage(tok, isPointer, alloc, _tokenizer->isCPP()))
return true;
return false;

View File

@ -57,13 +57,13 @@ public:
/** Check for uninitialized variables */
void check();
void checkScope(const Scope* scope);
bool checkScopeForVariable(const Scope* scope, const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, const std::string &membervar);
bool checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, const std::string &membervar);
bool checkLoopBody(const Token *tok, const Variable& var, const std::string &membervar, const bool suppressErrors);
void checkRhs(const Token *tok, const Variable &var, const std::string &membervar);
static bool isVariableUsage(const Token *vartok, bool ispointer, bool cpp);
bool checkScopeForVariable(const Scope* scope, const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, bool * const alloc, const std::string &membervar);
bool checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, bool alloc, const std::string &membervar);
bool checkLoopBody(const Token *tok, const Variable& var, const bool alloc, const std::string &membervar, const bool suppressErrors);
void checkRhs(const Token *tok, const Variable &var, bool alloc, const std::string &membervar);
static bool isVariableUsage(const Token *vartok, bool ispointer, bool alloc, bool cpp);
static bool isMemberVariableAssignment(const Token *tok, const std::string &membervar);
bool isMemberVariableUsage(const Token *tok, bool isPointer, const std::string &membervar) const;
bool isMemberVariableUsage(const Token *tok, bool isPointer, bool alloc, const std::string &membervar) const;
/**
* @brief Uninitialized variables: analyse functions to see how they work with uninitialized variables

View File

@ -64,6 +64,7 @@ private:
TEST_CASE(uninitvar2_structmembers); // struct members
TEST_CASE(uninitvar2_while);
TEST_CASE(uninitvar2_4494); // #4494
TEST_CASE(uninitvar2_malloc); // malloc returns uninitialized data
TEST_CASE(syntax_error); // Ticket #5073
}
@ -2047,6 +2048,7 @@ private:
// Tokenize..
Settings settings;
settings.debugwarnings = debugwarnings;
settings.library.returnuninitdata.insert("malloc");
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, fname);
@ -2909,6 +2911,35 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
checkUninitVar2("struct AB { int a; int b; };\n"
"int f() {\n"
" struct AB *ab;\n"
" for (i = 1; i < 10; i++) {\n"
" if (condition && (ab = getab()) != NULL) {\n"
" a = ab->a;\n"
" }\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar2("struct AB { int a; int b; };\n"
"int f(int x) {\n"
" struct AB *ab;\n"
" if (x == 0) {\n"
" ab = getab();\n"
" }\n"
" if (x == 0 && (ab != NULL || ab->a == 0)) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar2("struct A { int *x; };\n" // declarationId is 0 for "delete"
"void foo(void *info, void*p);\n"
"void bar(void) {\n"
" struct A *delete = 0;\n"
" foo( info, NULL );\n"
"}");
ASSERT_EQUALS("", errout.str());
// return
checkUninitVar2("struct AB { int a; int b; };\n"
"void f(void) {\n"
@ -3204,6 +3235,27 @@ private:
ASSERT_EQUALS("[test.cpp:20]: (error) Uninitialized variable: p\n", errout.str());
}
void uninitvar2_malloc() {
checkUninitVar2("int f() {\n"
" int *p = malloc(40);\n"
" return *p;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: p\n", errout.str());
checkUninitVar2("int f() {\n"
" int *p = malloc(40);\n"
" var = *p;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: p\n", errout.str());
checkUninitVar2("struct AB { int a; int b; };\n"
"int f() {\n"
" struct AB *ab = malloc(sizeof(struct AB));\n"
" return ab->a;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized struct member: ab.a\n", errout.str());
}
void syntax_error() { // Ticket #5073
// Nominal mode => No output
checkUninitVar2("struct flex_array {};\n"