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...
// * var = (char *)malloc(10);
@ -87,6 +87,10 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2)
return Malloc;
}
// Using realloc..
if (Token::Match(tok2, (std::string("realloc ( !!") + varname).c_str()))
return Malloc;
// Does tok2 point on "g_malloc", "g_strdup", ..
static const char * const gmallocfunc[] = {"g_new",
"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...
// * var = (char *)realloc(..;
@ -146,7 +150,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
if (! tok2)
return No;
if (tok2->str() == "realloc")
if (Token::Match(tok2, (std::string("realloc ( ") + varname).c_str()))
return Malloc;
// GTK memory reallocation..
@ -339,7 +343,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
if (varname.empty() && Token::Match(tok, "%var% = "))
{
varname = tok->str();
allocType = getAllocationType(tok->tokAt(2));
allocType = getAllocationType(tok->tokAt(2), varname.c_str());
if (allocType == No)
return No;
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"))
return 0;
// Keywords that are not function calls..
if (Token::Match(tok, "realloc"))
return 0;
// 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"))
return 0;
@ -457,7 +465,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
if (tok->str() == "delete")
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;
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()))
{
AllocType alloc = getAllocationType(tok->tokAt(2));
AllocType alloc = getAllocationType(tok->tokAt(2), varname);
bool realloc = false;
if (sz > 1 &&
@ -626,7 +634,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
if (alloc == No)
{
alloc = getReallocationType(tok->tokAt(2));
alloc = getReallocationType(tok->tokAt(2), varname);
if (alloc != No)
{
addtoken("realloc");
@ -947,7 +955,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
}
else
{
if (getReallocationType(tok) != No &&
if (getReallocationType(tok, varname) != No &&
Token::simpleMatch(tok->tokAt(2), varnameStr.c_str())
)
{
@ -1879,7 +1887,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
// Allocate..
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 != No && Alloc != alloc)

View File

@ -94,12 +94,12 @@ public:
/**
* 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
*/
AllocType getReallocationType(const Token *tok2);
AllocType getReallocationType(const Token *tok2, const char varname[]);
bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const;

View File

@ -19,7 +19,9 @@
#include "../src/tokenize.h"
#define private public
#include "../src/checkmemoryleak.h"
#undef private
#include "testsuite.h"
#include <sstream>
@ -223,6 +225,7 @@ private:
TEST_CASE(realloc3);
TEST_CASE(realloc4);
TEST_CASE(realloc5);
TEST_CASE(realloc6);
TEST_CASE(assign);
@ -1695,6 +1698,36 @@ private:
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()
{
check("void foo()\n"