Fixed #1789 (false positive: memory leak (reallocation in subfunction through parameter))

Detecting reallocations in the other function.
This commit is contained in:
Leandro Lisboa Penz 2010-06-16 22:29:55 -03:00
parent 8a6f4254e0
commit 58a872e6a0
3 changed files with 52 additions and 19 deletions

View File

@ -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.. // Find the varid of targetpar, then locate the start of the function..
unsigned int parlevel = 0; unsigned int parlevel = 0;
unsigned int par = 0; unsigned int par = 0;
unsigned int varid = 0; unsigned int varid = 0;
allocType = No;
while (tok) while (tok)
{ {
if (tok->str() == "{" || tok->str() == "}") if (tok->str() == "{" || tok->str() == "}")
return No; return "";
if (tok->str() == "(") if (tok->str() == "(")
{ {
if (parlevel != 0) if (parlevel != 0)
return No; return "";
++parlevel; ++parlevel;
++par; ++par;
} }
@ -484,7 +486,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, u
else if (tok->str() == ")") else if (tok->str() == ")")
{ {
if (parlevel != 1) if (parlevel != 1)
return No; return "";
break; break;
} }
@ -502,19 +504,33 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, u
} }
if (varid == 0) if (varid == 0)
return No; return "";
// Is this the start of a function? // Is this the start of a function?
if (!Token::Match(tok, ") const| {")) if (!Token::Match(tok, ") const| {"))
return No; return "";
while (tok->str() != "{") while (tok->str() != "{")
tok = tok->next(); tok = tok->next();
// Check if pointer is allocated. // Check if pointer is allocated.
AllocType allocType = No; unsigned int indentlevel = 0;
int realloc = 0;
while (0 != (tok = tok->next())) 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)) if (Token::Match(tok, "* %varid% =", varid))
{ {
allocType = getAllocationType(tok->tokAt(3), varid); allocType = getAllocationType(tok->tokAt(3), varid);
@ -524,14 +540,16 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionArgAlloc(const Token *tok, u
} }
if (allocType != No) if (allocType != No)
{ {
return allocType; if (realloc)
return "realloc";
return "alloc";
} }
} }
if (tok->str() == "return") if (tok->str() == "return")
return allocType; return "";
} }
return No; return "";
} }
@ -764,7 +782,8 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
if (varid > 0 && Token::Match(tok, "[,()] & %varid% [,()]", varid)) if (varid > 0 && Token::Match(tok, "[,()] & %varid% [,()]", varid))
{ {
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str()); 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) if (a != No)
{ {
@ -773,7 +792,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
else if (alloctype != a) else if (alloctype != a)
alloctype = Many; alloctype = Many;
allocpar = true; allocpar = true;
return "alloc"; return ret;
} }
} }
} }
@ -1325,7 +1344,12 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
const char *str = call_func(tok, callstack, varid, alloctype, dealloctype, allocpar, sz); const char *str = call_func(tok, callstack, varid, alloctype, dealloctype, allocpar, sz);
if (str) if (str)
{ {
if (varid == 0 || str != std::string("alloc")) if (allocpar)
{
addtoken(str);
tok = tok->next()->link();
}
else if (varid == 0 || str != std::string("alloc"))
{ {
addtoken(str); addtoken(str);
} }
@ -1333,11 +1357,6 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
{ {
addtoken(str); addtoken(str);
} }
else if (allocpar)
{
addtoken(str);
tok = tok->next()->link();
}
} }
else if (varid > 0 && else if (varid > 0 &&
getReallocationType(tok, varid) != No && getReallocationType(tok, varid) != No &&

View File

@ -146,7 +146,7 @@ public:
AllocType functionReturnType(const Token *tok) const; AllocType functionReturnType(const Token *tok) const;
/** Function allocates pointed-to argument (a la asprintf)? */ /** 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;
}; };
/// @} /// @}

View File

@ -1774,6 +1774,20 @@ private:
" foo(&p);\n" " foo(&p);\n"
"}\n"); "}\n");
TODO_ASSERT_EQUALS(std::string("[test.cpp:11]: (error) Memory leak: p\n"), errout.str()); 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());
} }