Memory leak: Mismatching allocation and deallocation in subfunction
This commit is contained in:
parent
8dab130d3e
commit
2ecb805283
|
@ -186,9 +186,7 @@ AllocType CheckMemoryLeakClass::GetDeallocationType( const TOKEN *tok, const cha
|
||||||
}
|
}
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
static std::list<std::string> callstack;
|
const char * CheckMemoryLeakClass::call_func( const TOKEN *tok, std::list<const TOKEN *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype )
|
||||||
|
|
||||||
const char * CheckMemoryLeakClass::call_func( const TOKEN *tok, const char *varnames[] )
|
|
||||||
{
|
{
|
||||||
if (Match(tok,"if") || Match(tok,"for") || Match(tok,"while"))
|
if (Match(tok,"if") || Match(tok,"for") || Match(tok,"while"))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -197,9 +195,9 @@ const char * CheckMemoryLeakClass::call_func( const TOKEN *tok, const char *varn
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const char *funcname = tok->str;
|
const char *funcname = tok->str;
|
||||||
if ( std::find(callstack.begin(), callstack.end(), std::string(funcname)) != callstack.end() )
|
if ( std::find(callstack.begin(), callstack.end(), tok) != callstack.end() )
|
||||||
return "use";
|
return "use";
|
||||||
callstack.push_back(funcname);
|
callstack.push_back(tok);
|
||||||
|
|
||||||
int par = 1;
|
int par = 1;
|
||||||
int parlevel = 0;
|
int parlevel = 0;
|
||||||
|
@ -227,7 +225,7 @@ const char * CheckMemoryLeakClass::call_func( const TOKEN *tok, const char *varn
|
||||||
// Check if the function deallocates the variable..
|
// Check if the function deallocates the variable..
|
||||||
while ( ftok && ! Match(ftok,"{") )
|
while ( ftok && ! Match(ftok,"{") )
|
||||||
ftok = ftok->next;
|
ftok = ftok->next;
|
||||||
TOKEN *func = getcode( Tokenizer::gettok(ftok,1), parname );
|
TOKEN *func = getcode( Tokenizer::gettok(ftok,1), callstack, parname, alloctype, dealloctype );
|
||||||
simplifycode( func );
|
simplifycode( func );
|
||||||
const char *ret = 0;
|
const char *ret = 0;
|
||||||
if (findmatch(func, "goto"))
|
if (findmatch(func, "goto"))
|
||||||
|
@ -246,9 +244,11 @@ const char * CheckMemoryLeakClass::call_func( const TOKEN *tok, const char *varn
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
void CheckMemoryLeakClass::MismatchError( const TOKEN *Tok1, const char varname[] )
|
void CheckMemoryLeakClass::MismatchError( const TOKEN *Tok1, const std::list<const TOKEN *> &callstack, const char varname[] )
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
|
for ( std::list<const TOKEN *>::const_iterator tok = callstack.begin(); tok != callstack.end(); ++tok )
|
||||||
|
errmsg << FileLine(*tok, _tokenizer) << " -> ";
|
||||||
errmsg << FileLine(Tok1, _tokenizer) << ": Mismatching allocation and deallocation: " << varname;
|
errmsg << FileLine(Tok1, _tokenizer) << ": Mismatching allocation and deallocation: " << varname;
|
||||||
ReportErr( errmsg.str() );
|
ReportErr( errmsg.str() );
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ extern bool ShowAll;
|
||||||
* varname - name of variable
|
* varname - name of variable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, const char varname[])
|
TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype)
|
||||||
{
|
{
|
||||||
const char *varnames[2];
|
const char *varnames[2];
|
||||||
varnames[0] = varname;
|
varnames[0] = varname;
|
||||||
|
@ -311,9 +311,6 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, const char varname[])
|
||||||
rettail=newtok; \
|
rettail=newtok; \
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocType alloctype = No;
|
|
||||||
AllocType dealloctype = No;
|
|
||||||
|
|
||||||
bool isloop = false;
|
bool isloop = false;
|
||||||
|
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
|
@ -360,9 +357,9 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, const char varname[])
|
||||||
{
|
{
|
||||||
addtoken("alloc");
|
addtoken("alloc");
|
||||||
if (alloctype!=No && alloctype!=alloc)
|
if (alloctype!=No && alloctype!=alloc)
|
||||||
MismatchError(tok, varname);
|
MismatchError(tok, callstack, varname);
|
||||||
if (dealloctype!=No && dealloctype!=alloc)
|
if (dealloctype!=No && dealloctype!=alloc)
|
||||||
MismatchError(tok, varname);
|
MismatchError(tok, callstack, varname);
|
||||||
alloctype = alloc;
|
alloctype = alloc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,9 +369,9 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, const char varname[])
|
||||||
{
|
{
|
||||||
addtoken("dealloc");
|
addtoken("dealloc");
|
||||||
if (alloctype!=No && alloctype!=dealloc)
|
if (alloctype!=No && alloctype!=dealloc)
|
||||||
MismatchError(tok, varname);
|
MismatchError(tok, callstack, varname);
|
||||||
if (dealloctype!=No && dealloctype!=dealloc)
|
if (dealloctype!=No && dealloctype!=dealloc)
|
||||||
MismatchError(tok, varname);
|
MismatchError(tok, callstack, varname);
|
||||||
dealloctype = dealloc;
|
dealloctype = dealloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +450,7 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, const char varname[])
|
||||||
// Investigate function calls..
|
// Investigate function calls..
|
||||||
if ( Match(tok, "%var% (") )
|
if ( Match(tok, "%var% (") )
|
||||||
{
|
{
|
||||||
const char *str = call_func(tok, varnames);
|
const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype);
|
||||||
if ( str )
|
if ( str )
|
||||||
addtoken( str );
|
addtoken( str );
|
||||||
}
|
}
|
||||||
|
@ -767,9 +764,12 @@ void CheckMemoryLeakClass::simplifycode(TOKEN *tok)
|
||||||
// Simpler but less powerful than "CheckMemoryLeak_CheckScope_All"
|
// Simpler but less powerful than "CheckMemoryLeak_CheckScope_All"
|
||||||
void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] )
|
void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] )
|
||||||
{
|
{
|
||||||
callstack.clear();
|
std::list<const TOKEN *> callstack;
|
||||||
|
|
||||||
TOKEN *tok = getcode( Tok1, varname );
|
AllocType alloctype = No;
|
||||||
|
AllocType dealloctype = No;
|
||||||
|
|
||||||
|
TOKEN *tok = getcode( Tok1, callstack, varname, alloctype, dealloctype );
|
||||||
|
|
||||||
// If the variable is not allocated at all => no memory leak
|
// If the variable is not allocated at all => no memory leak
|
||||||
if (findmatch(tok, "alloc") == 0)
|
if (findmatch(tok, "alloc") == 0)
|
||||||
|
@ -1009,10 +1009,11 @@ void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_Variable( const std::vec
|
||||||
AllocType alloc = GetAllocationType( Tokenizer::gettok( tok, 2 ) );
|
AllocType alloc = GetAllocationType( Tokenizer::gettok( tok, 2 ) );
|
||||||
if ( alloc != No )
|
if ( alloc != No )
|
||||||
{
|
{
|
||||||
|
std::list<const TOKEN *> callstack;
|
||||||
if ( Dealloc != No && Dealloc != alloc )
|
if ( Dealloc != No && Dealloc != alloc )
|
||||||
MismatchError( tok, FullVariableName.str().c_str() );
|
MismatchError( tok, callstack, FullVariableName.str().c_str() );
|
||||||
if ( Alloc != No && Alloc != alloc )
|
if ( Alloc != No && Alloc != alloc )
|
||||||
MismatchError( tok, FullVariableName.str().c_str() );
|
MismatchError( tok, callstack, FullVariableName.str().c_str() );
|
||||||
Alloc = alloc;
|
Alloc = alloc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1023,10 +1024,11 @@ void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_Variable( const std::vec
|
||||||
AllocType dealloc = GetDeallocationType( tok, varnames );
|
AllocType dealloc = GetDeallocationType( tok, varnames );
|
||||||
if ( dealloc != No )
|
if ( dealloc != No )
|
||||||
{
|
{
|
||||||
|
std::list<const TOKEN *> callstack;
|
||||||
if ( Dealloc != No && Dealloc != dealloc )
|
if ( Dealloc != No && Dealloc != dealloc )
|
||||||
MismatchError( tok, FullVariableName.str().c_str() );
|
MismatchError( tok, callstack, FullVariableName.str().c_str() );
|
||||||
if ( Alloc != No && Alloc != dealloc )
|
if ( Alloc != No && Alloc != dealloc )
|
||||||
MismatchError( tok, FullVariableName.str().c_str() );
|
MismatchError( tok, callstack, FullVariableName.str().c_str() );
|
||||||
Dealloc = dealloc;
|
Dealloc = dealloc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,9 @@
|
||||||
|
|
||||||
/** \brief Check for memory leaks */
|
/** \brief Check for memory leaks */
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
enum AllocType { No, Malloc, gMalloc, New, NewA };
|
enum AllocType { No, Malloc, gMalloc, New, NewA };
|
||||||
|
|
||||||
|
@ -46,13 +47,13 @@ private:
|
||||||
void simplifycode(TOKEN *tok);
|
void simplifycode(TOKEN *tok);
|
||||||
void erase(TOKEN *begin, const TOKEN *end);
|
void erase(TOKEN *begin, const TOKEN *end);
|
||||||
|
|
||||||
TOKEN *getcode(const TOKEN *tok, const char varname[]);
|
TOKEN *getcode(const TOKEN *tok, std::list<const TOKEN *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype);
|
||||||
bool notvar(const TOKEN *tok, const char *varnames[]);
|
bool notvar(const TOKEN *tok, const char *varnames[]);
|
||||||
void instoken(TOKEN *tok, const char str[]);
|
void instoken(TOKEN *tok, const char str[]);
|
||||||
void MemoryLeak( const TOKEN *tok, const char varname[] );
|
void MemoryLeak( const TOKEN *tok, const char varname[] );
|
||||||
void MismatchError( const TOKEN *Tok1, const char varname[] );
|
void MismatchError( const TOKEN *Tok1, const std::list<const TOKEN *> &callstack, const char varname[] );
|
||||||
const char * call_func( const TOKEN *tok, const char *varnames[] );
|
const char * call_func( const TOKEN *tok, std::list<const TOKEN *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype );
|
||||||
AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[] );
|
AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[]);
|
||||||
AllocType GetAllocationType( const TOKEN *tok2 );
|
AllocType GetAllocationType( const TOKEN *tok2 );
|
||||||
bool isclass( const std::string &typestr );
|
bool isclass( const std::string &typestr );
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ private:
|
||||||
TEST_CASE( func2 );
|
TEST_CASE( func2 );
|
||||||
TEST_CASE( func3 );
|
TEST_CASE( func3 );
|
||||||
TEST_CASE( func4 );
|
TEST_CASE( func4 );
|
||||||
// TODO TEST_CASE( func5 );
|
TEST_CASE( func5 );
|
||||||
|
|
||||||
TEST_CASE( class1 );
|
TEST_CASE( class1 );
|
||||||
TEST_CASE( class2 );
|
TEST_CASE( class2 );
|
||||||
|
@ -711,7 +711,8 @@ private:
|
||||||
" char *p = new char[100];\n"
|
" char *p = new char[100];\n"
|
||||||
" foo(p);\n"
|
" foo(p);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string("mismatching allocation and deallocation"), errout.str() );
|
std::string err( errout.str() );
|
||||||
|
ASSERT_EQUALS( std::string("[test.cpp:9] -> [test.cpp:3]: Mismatching allocation and deallocation: str\n"), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue