diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index bd49b6975..883831dc8 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -461,22 +461,24 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) } -CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, unsigned int targetpar) const +const char *CheckMemoryLeak::functionArgAlloc(const Token *tok, unsigned int targetpar, AllocType &allocType) const { // Find the varid of targetpar, then locate the start of the function.. unsigned int parlevel = 0; unsigned int par = 0; unsigned int varid = 0; + allocType = No; + while (tok) { if (tok->str() == "{" || tok->str() == "}") - return No; + return ""; if (tok->str() == "(") { if (parlevel != 0) - return No; + return ""; ++parlevel; ++par; } @@ -484,7 +486,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, u else if (tok->str() == ")") { if (parlevel != 1) - return No; + return ""; break; } @@ -502,19 +504,33 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, u } if (varid == 0) - return No; + return ""; // Is this the start of a function? if (!Token::Match(tok, ") const| {")) - return No; + return ""; while (tok->str() != "{") tok = tok->next(); // Check if pointer is allocated. - AllocType allocType = No; + unsigned int indentlevel = 0; + int realloc = 0; while (0 != (tok = tok->next())) { + if (tok->str() == "{") + ++indentlevel; + else if (tok->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + if (Token::Match(tok, "free ( * %varid% )", varid)) + { + realloc = 1; + allocType = No; + } if (Token::Match(tok, "* %varid% =", varid)) { allocType = getAllocationType(tok->tokAt(3), varid); @@ -524,14 +540,16 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, u } if (allocType != No) { - return allocType; + if (realloc) + return "realloc"; + return "alloc"; } } if (tok->str() == "return") - return allocType; + return ""; } - return No; + return ""; } @@ -764,7 +782,8 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list 0 && Token::Match(tok, "[,()] & %varid% [,()]", varid)) { const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str()); - AllocType a = functionArgAlloc(ftok, par); + AllocType a; + const char *ret = functionArgAlloc(ftok, par, a); if (a != No) { @@ -773,7 +792,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::listnext()->link(); + } + else if (varid == 0 || str != std::string("alloc")) { addtoken(str); } @@ -1333,11 +1357,6 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listnext()->link(); - } } else if (varid > 0 && getReallocationType(tok, varid) != No && diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index b5a31c55b..d152906d9 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -146,7 +146,7 @@ public: AllocType functionReturnType(const Token *tok) const; /** Function allocates pointed-to argument (a la asprintf)? */ - AllocType functionArgAlloc(const Token *tok, unsigned int parlevel0) const; + const char *functionArgAlloc(const Token *tok, unsigned int targetpar, AllocType &allocType) const; }; /// @} diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index d7441c342..a2bd6ff82 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -1774,6 +1774,20 @@ private: " foo(&p);\n" "}\n"); TODO_ASSERT_EQUALS(std::string("[test.cpp:11]: (error) Memory leak: p\n"), errout.str()); + + check("void foo(char **str)\n" + "{\n" + " free(*str);\n" + " *str = malloc(20);\n" + "}\n" + "\n" + "void bar()\n" + "{\n" + " char *tmp = malloc(10);\n" + " foo(&tmp);\n" + " free(tmp);\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); }