diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index da92c4aaa..3ae3c9a2f 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1092,33 +1092,23 @@ void CheckUninitVar::checkScope(const Scope* scope) 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) { - const Scope *scope2 = symbolDatabase->classAndStructScopes[j]; - if (scope2->className == structname && scope2->numConstructors == 0U) { - for (std::list::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::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 (Token::Match(i->typeStartToken(), "struct %type% *| %var% ;")) + checkStruct(scope, tok, *i); + } - } - } - - if (!innerunion) { - bool alloc = false; - checkScopeForVariable(scope, tok, *i, NULL, NULL, &alloc, var.name()); - } + if (scope->function) { + for (unsigned int i = 0; i < scope->function->argCount(); i++) { + const Variable *arg = scope->function->getArgumentVar(i); + if (arg && Token::Match(arg->typeStartToken(), "struct| %type% * %var% [,)]")) { + // Treat the pointer as initialized until it is assigned by malloc + 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::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::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 &variableValue, bool *alwaysTrue, bool *alwaysFalse) { assert(Token::simpleMatch(tok, "if (")); diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index 0da0ad810..10040d71c 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -57,6 +57,7 @@ public: /** Check for uninitialized variables */ void check(); 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 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); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index e2be41b38..744f768d9 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -3254,6 +3254,22 @@ private: " return ab->a;\n" "}"); 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