Fixed #1789 (false positive: memory leak (reallocation in subfunction through parameter))
Detecting reallocations in the other function.
This commit is contained in:
parent
8a6f4254e0
commit
58a872e6a0
|
@ -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 &&
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue