Uninitialized variables: check function arguments
This commit is contained in:
parent
f686cd6516
commit
be5c00d215
|
@ -1092,33 +1092,23 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
bool alloc = false;
|
bool alloc = false;
|
||||||
checkScopeForVariable(scope, tok, *i, NULL, NULL, &alloc, "");
|
checkScopeForVariable(scope, tok, *i, NULL, NULL, &alloc, "");
|
||||||
}
|
}
|
||||||
if (Token::Match(i->typeStartToken(), "struct %type% *| %var% ;")) {
|
if (Token::Match(i->typeStartToken(), "struct %type% *| %var% ;"))
|
||||||
const std::string structname(i->typeStartToken()->next()->str());
|
checkStruct(scope, tok, *i);
|
||||||
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
|
}
|
||||||
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
|
|
||||||
const Scope *scope2 = symbolDatabase->classAndStructScopes[j];
|
|
||||||
if (scope2->className == structname && scope2->numConstructors == 0U) {
|
|
||||||
for (std::list<Variable>::const_iterator it = scope2->varlist.begin(); it != scope2->varlist.end(); ++it) {
|
|
||||||
const Variable &var = *it;
|
|
||||||
if (!var.isArray()) {
|
|
||||||
// is the variable declared in a inner union?
|
|
||||||
bool innerunion = false;
|
|
||||||
for (std::list<Scope>::const_iterator it2 = symbolDatabase->scopeList.begin(); it2 != symbolDatabase->scopeList.end(); ++it2) {
|
|
||||||
const Scope &innerScope = *it2;
|
|
||||||
if (innerScope.type == Scope::eUnion && innerScope.nestedIn == scope2) {
|
|
||||||
if (var.typeStartToken()->linenr() >= innerScope.classStart->linenr() &&
|
|
||||||
var.typeStartToken()->linenr() <= innerScope.classEnd->linenr()) {
|
|
||||||
innerunion = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
if (scope->function) {
|
||||||
}
|
for (unsigned int i = 0; i < scope->function->argCount(); i++) {
|
||||||
|
const Variable *arg = scope->function->getArgumentVar(i);
|
||||||
if (!innerunion) {
|
if (arg && Token::Match(arg->typeStartToken(), "struct| %type% * %var% [,)]")) {
|
||||||
bool alloc = false;
|
// Treat the pointer as initialized until it is assigned by malloc
|
||||||
checkScopeForVariable(scope, tok, *i, NULL, NULL, &alloc, var.name());
|
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
|
||||||
}
|
if (Token::Match(tok, "[;{}] %varid% = %var% (", arg->declarationId()) &&
|
||||||
|
_settings->library.returnuninitdata.count(tok->strAt(3)) == 1U) {
|
||||||
|
if (arg->typeStartToken()->str() == "struct")
|
||||||
|
checkStruct(scope, tok, *arg);
|
||||||
|
else if (arg->typeStartToken()->isStandardType()) {
|
||||||
|
bool alloc = false;
|
||||||
|
checkScopeForVariable(scope, tok->next(), *arg, NULL, NULL, &alloc, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1127,6 +1117,46 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckUninitVar::checkStruct(const Scope* scope, const Token *tok, const Variable &structvar)
|
||||||
|
{
|
||||||
|
const Token *typeToken = structvar.typeStartToken();
|
||||||
|
if (typeToken->str() == "struct")
|
||||||
|
typeToken = typeToken->next();
|
||||||
|
const std::string structname(typeToken->str());
|
||||||
|
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
|
||||||
|
const Scope *scope2 = symbolDatabase->classAndStructScopes[j];
|
||||||
|
if (scope2->className == structname && scope2->numConstructors == 0U) {
|
||||||
|
for (std::list<Variable>::const_iterator it = scope2->varlist.begin(); it != scope2->varlist.end(); ++it) {
|
||||||
|
const Variable &var = *it;
|
||||||
|
if (!var.isArray()) {
|
||||||
|
// is the variable declared in a inner union?
|
||||||
|
bool innerunion = false;
|
||||||
|
for (std::list<Scope>::const_iterator it2 = symbolDatabase->scopeList.begin(); it2 != symbolDatabase->scopeList.end(); ++it2) {
|
||||||
|
const Scope &innerScope = *it2;
|
||||||
|
if (innerScope.type == Scope::eUnion && innerScope.nestedIn == scope2) {
|
||||||
|
if (var.typeStartToken()->linenr() >= innerScope.classStart->linenr() &&
|
||||||
|
var.typeStartToken()->linenr() <= innerScope.classEnd->linenr()) {
|
||||||
|
innerunion = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!innerunion) {
|
||||||
|
bool alloc = false;
|
||||||
|
const Token *tok2 = tok;
|
||||||
|
if (tok->str() == "}")
|
||||||
|
tok2 = tok2->next();
|
||||||
|
checkScopeForVariable(scope, tok2, structvar, NULL, NULL, &alloc, var.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<unsigned int, int> &variableValue, bool *alwaysTrue, bool *alwaysFalse)
|
static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<unsigned int, int> &variableValue, bool *alwaysTrue, bool *alwaysFalse)
|
||||||
{
|
{
|
||||||
assert(Token::simpleMatch(tok, "if ("));
|
assert(Token::simpleMatch(tok, "if ("));
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
/** Check for uninitialized variables */
|
/** Check for uninitialized variables */
|
||||||
void check();
|
void check();
|
||||||
void checkScope(const Scope* scope);
|
void checkScope(const Scope* scope);
|
||||||
|
void checkStruct(const Scope* scope, const Token *tok, const Variable &structvar);
|
||||||
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 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 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);
|
bool checkLoopBody(const Token *tok, const Variable& var, const bool alloc, const std::string &membervar, const bool suppressErrors);
|
||||||
|
|
|
@ -3254,6 +3254,22 @@ private:
|
||||||
" return ab->a;\n"
|
" return ab->a;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized struct member: ab.a\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized struct member: ab.a\n", errout.str());
|
||||||
|
|
||||||
|
// function parameter (treat it as initialized until malloc is used)
|
||||||
|
checkUninitVar2("int f(int *p) {\n"
|
||||||
|
" if (*p == 1) {}\n" // no error
|
||||||
|
" p = malloc(256);\n"
|
||||||
|
" return *p;\n" // error
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) Memory is allocated but not initialized: p\n", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar2("struct AB { int a; int b; };\n"
|
||||||
|
"int f(struct AB *ab) {\n"
|
||||||
|
" if (ab->a == 1) {}\n" // no error
|
||||||
|
" ab = malloc(sizeof(struct AB));\n"
|
||||||
|
" return ab->a;\n" // error
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized struct member: ab.a\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void syntax_error() { // Ticket #5073
|
void syntax_error() { // Ticket #5073
|
||||||
|
|
Loading…
Reference in New Issue