Memory leaks: Improved handling of allocation functions that contains ::. Ticket: #4494

This commit is contained in:
Daniel Marjamäki 2013-01-22 21:33:39 +01:00
parent 444f80c4bb
commit f86e83d813
2 changed files with 85 additions and 68 deletions

View File

@ -140,80 +140,86 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
if (! tok2->isName())
return No;
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
static const char * const mallocfunc[] = {
"malloc",
"calloc",
"strdup",
"strndup",
"kmalloc",
"kzalloc",
"kcalloc"
};
for (unsigned int i = 0; i < sizeof(mallocfunc)/sizeof(*mallocfunc); i++) {
if (tok2->str() == mallocfunc[i])
return Malloc;
}
// Using realloc..
if (varid && Token::Match(tok2, "realloc ( %any% ,") && tok2->tokAt(2)->varId() != varid)
return Malloc;
// Does tok2 point on "g_malloc", "g_strdup", ..
static const char * const gmallocfunc[] = {
"g_new",
"g_new0",
"g_try_new",
"g_try_new0",
"g_malloc",
"g_malloc0",
"g_try_malloc",
"g_try_malloc0",
"g_strdup",
"g_strndup",
"g_strdup_printf"
};
for (unsigned int i = 0; i < sizeof(gmallocfunc)/sizeof(*gmallocfunc); i++) {
if (tok2->str() == gmallocfunc[i])
return gMalloc;
}
if (Token::Match(tok2, "new struct| %type% [;()]") ||
Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [;()]") ||
Token::Match(tok2, "new ( nothrow ) struct| %type% [;()]"))
return New;
if (Token::Match(tok2, "new struct| %type% [") ||
Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [") ||
Token::Match(tok2, "new ( nothrow ) struct| %type% ["))
return NewArray;
if (Token::Match(tok2, "fopen|tmpfile|g_fopen ("))
return File;
if (standards.posix) {
if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp (")) {
// simple sanity check of function parameters..
// TODO: Make such check for all these functions
unsigned int num = countParameters(tok2);
if (tok2->str() == "open" && num != 2 && num != 3)
return No;
// is there a user function with this name?
if (tokenizer && Token::findmatch(tokenizer->tokens(), ("%type% *|&| " + tok2->str()).c_str()))
return No;
return Fd;
if (!Token::Match(tok2, "%type% :: %type%")) {
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
static const char * const mallocfunc[] = {
"malloc",
"calloc",
"strdup",
"strndup",
"kmalloc",
"kzalloc",
"kcalloc"
};
for (unsigned int i = 0; i < sizeof(mallocfunc)/sizeof(*mallocfunc); i++) {
if (tok2->str() == mallocfunc[i])
return Malloc;
}
if (Token::simpleMatch(tok2, "popen ("))
return Pipe;
// Using realloc..
if (varid && Token::Match(tok2, "realloc ( %any% ,") && tok2->tokAt(2)->varId() != varid)
return Malloc;
// Does tok2 point on "g_malloc", "g_strdup", ..
static const char * const gmallocfunc[] = {
"g_new",
"g_new0",
"g_try_new",
"g_try_new0",
"g_malloc",
"g_malloc0",
"g_try_malloc",
"g_try_malloc0",
"g_strdup",
"g_strndup",
"g_strdup_printf"
};
for (unsigned int i = 0; i < sizeof(gmallocfunc)/sizeof(*gmallocfunc); i++) {
if (tok2->str() == gmallocfunc[i])
return gMalloc;
}
if (Token::Match(tok2, "new struct| %type% [;()]") ||
Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [;()]") ||
Token::Match(tok2, "new ( nothrow ) struct| %type% [;()]"))
return New;
if (Token::Match(tok2, "new struct| %type% [") ||
Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [") ||
Token::Match(tok2, "new ( nothrow ) struct| %type% ["))
return NewArray;
if (Token::Match(tok2, "fopen|tmpfile|g_fopen ("))
return File;
if (standards.posix) {
if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp (")) {
// simple sanity check of function parameters..
// TODO: Make such check for all these functions
unsigned int num = countParameters(tok2);
if (tok2->str() == "open" && num != 2 && num != 3)
return No;
// is there a user function with this name?
if (tokenizer && Token::findmatch(tokenizer->tokens(), ("%type% *|&| " + tok2->str()).c_str()))
return No;
return Fd;
}
if (Token::simpleMatch(tok2, "popen ("))
return Pipe;
if (Token::Match(tok2, "opendir|fdopendir ("))
return Dir;
}
if (Token::Match(tok2, "opendir|fdopendir ("))
return Dir;
}
while (Token::Match(tok2,"%type% :: %type%"))
tok2 = tok2->tokAt(2);
// User function
const Function* func = tokenizer->getSymbolDatabase()->findFunctionByName(tok2->str(), tok2->scope());
const Function* func = tokenizer->getSymbolDatabase()->findFunctionByNameAndArgs(tok2, tok2->scope());
if (func == NULL)
return No;

View File

@ -240,6 +240,7 @@ private:
TEST_CASE(allocfunc10);
TEST_CASE(allocfunc11);
TEST_CASE(allocfunc12); // #3660: allocating and returning non-local pointer => not allocfunc
TEST_CASE(allocfunc13); // Ticket #4494 - class function
TEST_CASE(throw1);
TEST_CASE(throw2);
@ -2583,6 +2584,16 @@ private:
ASSERT_EQUALS("", errout.str());
}
void allocfunc13() { // #4494: class function
check("namespace n {\n"
" char *a() { return malloc(100); }\n"
"}\n"
"void b() {\n"
" char *x = n::a();\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Memory leak: x\n", errout.str());
}
void throw1() {
check("void foo()\n"
"{\n"