Fixed #566 (False positive when assigning the return value of realloc(NULL,..) to a pointer variable holding a freed memory address)

This commit is contained in:
Daniel Marjamäki 2009-08-10 22:04:28 +02:00
parent 045b73c7ec
commit ecdbcbce3d
3 changed files with 52 additions and 11 deletions

View File

@ -53,7 +53,7 @@ bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) con
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2) const CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, const char varname[]) const
{ {
// What we may have... // What we may have...
// * var = (char *)malloc(10); // * var = (char *)malloc(10);
@ -87,6 +87,10 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2)
return Malloc; return Malloc;
} }
// Using realloc..
if (Token::Match(tok2, (std::string("realloc ( !!") + varname).c_str()))
return Malloc;
// Does tok2 point on "g_malloc", "g_strdup", .. // Does tok2 point on "g_malloc", "g_strdup", ..
static const char * const gmallocfunc[] = {"g_new", static const char * const gmallocfunc[] = {"g_new",
"g_new0", "g_new0",
@ -133,7 +137,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2)
CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2) CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, const char varname[])
{ {
// What we may have... // What we may have...
// * var = (char *)realloc(..; // * var = (char *)realloc(..;
@ -146,7 +150,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
if (! tok2) if (! tok2)
return No; return No;
if (tok2->str() == "realloc") if (Token::Match(tok2, (std::string("realloc ( ") + varname).c_str()))
return Malloc; return Malloc;
// GTK memory reallocation.. // GTK memory reallocation..
@ -339,7 +343,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
if (varname.empty() && Token::Match(tok, "%var% = ")) if (varname.empty() && Token::Match(tok, "%var% = "))
{ {
varname = tok->str(); varname = tok->str();
allocType = getAllocationType(tok->tokAt(2)); allocType = getAllocationType(tok->tokAt(2), varname.c_str());
if (allocType == No) if (allocType == No)
return No; return No;
while (tok && tok->str() != ";") while (tok && tok->str() != ";")
@ -424,6 +428,10 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
if (Token::Match(tok, "if|for|while|return|switch")) if (Token::Match(tok, "if|for|while|return|switch"))
return 0; return 0;
// Keywords that are not function calls..
if (Token::Match(tok, "realloc"))
return 0;
// String functions that are not allocating nor deallocating memory.. // String functions that are not allocating nor deallocating memory..
if (Token::Match(tok, "strcpy|strncpy|strcat|strncat|strcmp|strncmp|strcasecmp|stricmp|sprintf|strchr|strrchr|strstr")) if (Token::Match(tok, "strcpy|strncpy|strcat|strncat|strcmp|strncmp|strcasecmp|stricmp|sprintf|strchr|strrchr|strstr"))
return 0; return 0;
@ -457,7 +465,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
if (tok->str() == "delete") if (tok->str() == "delete")
return 0; return 0;
if (getAllocationType(tok) != No || getReallocationType(tok) != No || getDeallocationType(tok, varnames) != No) if (getAllocationType(tok, varnames[0]) != No || getReallocationType(tok, varnames[0]) != No || getDeallocationType(tok, varnames) != No)
return 0; return 0;
if (callstack.size() > 2) if (callstack.size() > 2)
@ -614,7 +622,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
if (Token::Match(tok->previous(), std::string("[(;{}] " + varnameStr + " =").c_str())) if (Token::Match(tok->previous(), std::string("[(;{}] " + varnameStr + " =").c_str()))
{ {
AllocType alloc = getAllocationType(tok->tokAt(2)); AllocType alloc = getAllocationType(tok->tokAt(2), varname);
bool realloc = false; bool realloc = false;
if (sz > 1 && if (sz > 1 &&
@ -626,7 +634,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
if (alloc == No) if (alloc == No)
{ {
alloc = getReallocationType(tok->tokAt(2)); alloc = getReallocationType(tok->tokAt(2), varname);
if (alloc != No) if (alloc != No)
{ {
addtoken("realloc"); addtoken("realloc");
@ -947,7 +955,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
} }
else else
{ {
if (getReallocationType(tok) != No && if (getReallocationType(tok, varname) != No &&
Token::simpleMatch(tok->tokAt(2), varnameStr.c_str()) Token::simpleMatch(tok->tokAt(2), varnameStr.c_str())
) )
{ {
@ -1879,7 +1887,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
// Allocate.. // Allocate..
if (indent == 0 || Token::Match(tok, (std::string(varname) + " =").c_str())) if (indent == 0 || Token::Match(tok, (std::string(varname) + " =").c_str()))
{ {
AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3)); AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3), varname);
if (alloc != CheckMemoryLeak::No) if (alloc != CheckMemoryLeak::No)
{ {
if (Alloc != No && Alloc != alloc) if (Alloc != No && Alloc != alloc)

View File

@ -94,12 +94,12 @@ public:
/** /**
* Get type of allocation at given position * Get type of allocation at given position
*/ */
AllocType getAllocationType(const Token *tok2) const; AllocType getAllocationType(const Token *tok2, const char varname[]) const;
/** /**
* Get type of reallocation at given position * Get type of reallocation at given position
*/ */
AllocType getReallocationType(const Token *tok2); AllocType getReallocationType(const Token *tok2, const char varname[]);
bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const; bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const;

View File

@ -19,7 +19,9 @@
#include "../src/tokenize.h" #include "../src/tokenize.h"
#define private public
#include "../src/checkmemoryleak.h" #include "../src/checkmemoryleak.h"
#undef private
#include "testsuite.h" #include "testsuite.h"
#include <sstream> #include <sstream>
@ -223,6 +225,7 @@ private:
TEST_CASE(realloc3); TEST_CASE(realloc3);
TEST_CASE(realloc4); TEST_CASE(realloc4);
TEST_CASE(realloc5); TEST_CASE(realloc5);
TEST_CASE(realloc6);
TEST_CASE(assign); TEST_CASE(assign);
@ -1695,6 +1698,36 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
std::string getcode(const char code[], const char varname[]) const
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
// getcode..
CheckMemoryLeakInFunction checkMemoryLeak;
std::list<const Token *> callstack;
CheckMemoryLeak::AllocType allocType, deallocType;
bool all = false;
Token *tokens = checkMemoryLeak.getcode(tokenizer.tokens(), callstack, varname, allocType, deallocType, false, all, 1);
// stringify..
std::string ret;
for (const Token *tok = tokens; tok; tok = tok->next())
ret += tok->str();
Tokenizer::deleteTokens(tokens);
return ret;
}
void realloc6()
{
ASSERT_EQUALS(";;realloc;;", getcode(";buf=realloc(buf,100);", "buf"));
ASSERT_EQUALS(";;alloc;", getcode(";buf=realloc(0,100);", "buf"));
}
void assign() void assign()
{ {
check("void foo()\n" check("void foo()\n"