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:
parent
045b73c7ec
commit
ecdbcbce3d
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue