Memory leaks: Use varid instead of varname
This commit is contained in:
parent
2ca5caab28
commit
8b46172bcf
|
@ -53,7 +53,7 @@ bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) con
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, const char varname[]) const
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, const unsigned int varid) const
|
||||||
{
|
{
|
||||||
// What we may have...
|
// What we may have...
|
||||||
// * var = (char *)malloc(10);
|
// * var = (char *)malloc(10);
|
||||||
|
@ -87,7 +87,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using realloc..
|
// Using realloc..
|
||||||
if (Token::Match(tok2, (std::string("realloc ( !!") + varname).c_str()))
|
if (varid && Token::Match(tok2, "realloc ( %any% ,") && tok2->tokAt(2)->varId() != varid)
|
||||||
return Malloc;
|
return Malloc;
|
||||||
|
|
||||||
// Does tok2 point on "g_malloc", "g_strdup", ..
|
// Does tok2 point on "g_malloc", "g_strdup", ..
|
||||||
|
@ -136,7 +136,8 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, const char varname[])
|
|
||||||
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, const unsigned int varid) const
|
||||||
{
|
{
|
||||||
// What we may have...
|
// What we may have...
|
||||||
// * var = (char *)realloc(..;
|
// * var = (char *)realloc(..;
|
||||||
|
@ -148,7 +149,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
|
||||||
if (! tok2)
|
if (! tok2)
|
||||||
return No;
|
return No;
|
||||||
|
|
||||||
if (! Token::Match(tok2, (std::string("%var% ( ") + varname + " [,)]").c_str()))
|
if (! Token::Match(tok2, "%var% ( %varid% [,)]", varid))
|
||||||
return No;
|
return No;
|
||||||
|
|
||||||
if (tok2->str() == "realloc")
|
if (tok2->str() == "realloc")
|
||||||
|
@ -162,7 +163,44 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const char *varnames[])
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const unsigned int varid) const
|
||||||
|
{
|
||||||
|
if (Token::Match(tok, "delete %varid% ;", varid))
|
||||||
|
return New;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "delete [ ] %varid% ;", varid))
|
||||||
|
return NewArray;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "delete ( %varid% ) ;", varid))
|
||||||
|
return New;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
|
||||||
|
return NewArray;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "free ( %varid% ) ;", varid) ||
|
||||||
|
Token::Match(tok, "kfree ( %varid% ) ;", varid))
|
||||||
|
return Malloc;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "g_free ( %varid% ) ;", varid))
|
||||||
|
return gMalloc;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "fclose ( %varid% )", varid) ||
|
||||||
|
Token::Match(tok, "fcloseall ( )"))
|
||||||
|
return File;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "close ( %varid% )", varid))
|
||||||
|
return Fd;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "pclose ( %varid% )", varid))
|
||||||
|
return Pipe;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "closedir ( %varid% )", varid))
|
||||||
|
return Dir;
|
||||||
|
|
||||||
|
return No;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const char *varnames[]) const
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
std::string names;
|
std::string names;
|
||||||
|
@ -214,17 +252,17 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
void CheckMemoryLeak::memoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all)
|
void CheckMemoryLeak::memoryLeak(const Token *tok, const std::string varname, AllocType alloctype, bool all)
|
||||||
{
|
{
|
||||||
if (alloctype == CheckMemoryLeak::File ||
|
if (alloctype == CheckMemoryLeak::File ||
|
||||||
alloctype == CheckMemoryLeak::Pipe ||
|
alloctype == CheckMemoryLeak::Pipe ||
|
||||||
alloctype == CheckMemoryLeak::Fd ||
|
alloctype == CheckMemoryLeak::Fd ||
|
||||||
alloctype == CheckMemoryLeak::Dir)
|
alloctype == CheckMemoryLeak::Dir)
|
||||||
resourceLeakError(tok, varname);
|
resourceLeakError(tok, varname.c_str());
|
||||||
else if (all)
|
else if (all)
|
||||||
memleakallError(tok, varname);
|
memleakallError(tok, varname.c_str());
|
||||||
else
|
else
|
||||||
memleakError(tok, varname);
|
memleakError(tok, varname.c_str());
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -330,7 +368,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
|
||||||
tok = tok ? tok->next() : 0;
|
tok = tok ? tok->next() : 0;
|
||||||
|
|
||||||
// Inspect the statements..
|
// Inspect the statements..
|
||||||
std::string varname;
|
unsigned int varid = 0;
|
||||||
AllocType allocType = No;
|
AllocType allocType = No;
|
||||||
while (tok)
|
while (tok)
|
||||||
{
|
{
|
||||||
|
@ -341,10 +379,10 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (varname.empty() && Token::Match(tok, "%var% = "))
|
if (varid == 0 && tok->varId() && Token::Match(tok, "%var% ="))
|
||||||
{
|
{
|
||||||
varname = tok->str();
|
varid = tok->varId();
|
||||||
allocType = getAllocationType(tok->tokAt(2), varname.c_str());
|
allocType = getAllocationType(tok->tokAt(2), varid);
|
||||||
if (allocType == No)
|
if (allocType == No)
|
||||||
return No;
|
return No;
|
||||||
while (tok && tok->str() != ";")
|
while (tok && tok->str() != ";")
|
||||||
|
@ -355,7 +393,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
|
||||||
|
|
||||||
if (tok->str() == "return")
|
if (tok->str() == "return")
|
||||||
{
|
{
|
||||||
if (varname.size() && Token::Match(tok->next(), (varname + " ;").c_str()))
|
if (varid > 0 && Token::Match(tok->next(), "%varid% ;", varid))
|
||||||
return allocType;
|
return allocType;
|
||||||
if (Token::Match(tok, "return new %type% ;"))
|
if (Token::Match(tok, "return new %type% ;"))
|
||||||
return New;
|
return New;
|
||||||
|
@ -398,27 +436,17 @@ void CheckMemoryLeakInFunction::init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckMemoryLeakInFunction::matchFunctionsThatReturnArg(const Token *tok, const std::string &varname)
|
bool CheckMemoryLeakInFunction::matchFunctionsThatReturnArg(const Token *tok, const unsigned int varid) const
|
||||||
{
|
{
|
||||||
return Token::Match(tok, std::string("; " + varname + " = strcat|memcpy|memmove|strcpy ( " + varname + " ,").c_str());
|
return Token::Match(tok, "; %varid% = strcat|memcpy|memmove|strcpy ( %varid% ,", varid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CheckMemoryLeakInFunction::notvar(const Token *tok, const char *varnames[], bool endpar)
|
bool CheckMemoryLeakInFunction::notvar(const Token *tok, const unsigned int varid, bool endpar) const
|
||||||
{
|
{
|
||||||
std::string varname;
|
|
||||||
for (int i = 0; varnames[i]; i++)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
varname += " . ";
|
|
||||||
|
|
||||||
varname += varnames[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string end(endpar ? " &&|)" : " [;)&|]");
|
const std::string end(endpar ? " &&|)" : " [;)&|]");
|
||||||
|
return bool(Token::Match(tok, ("! %varid%" + end).c_str(), varid) ||
|
||||||
return bool(Token::Match(tok, ("! " + varname + end).c_str()) ||
|
Token::Match(tok, ("! ( %varid% )" + end).c_str(), varid));
|
||||||
Token::Match(tok, ("! ( " + varname + " )" + end).c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -450,12 +478,12 @@ static int countParameters(const Token *tok)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz)
|
const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz)
|
||||||
{
|
{
|
||||||
if (call_func_white_list.find(tok->str()) != call_func_white_list.end())
|
if (call_func_white_list.find(tok->str()) != call_func_white_list.end())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (getAllocationType(tok, varnames[0]) != No || getReallocationType(tok, varnames[0]) != No || getDeallocationType(tok, varnames) != No)
|
if (getAllocationType(tok, varid) != No || getReallocationType(tok, varid) != No || getDeallocationType(tok, varid) != No)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (callstack.size() > 2)
|
if (callstack.size() > 2)
|
||||||
|
@ -484,16 +512,6 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
|
|
||||||
int par = 1;
|
int par = 1;
|
||||||
int parlevel = 0;
|
int parlevel = 0;
|
||||||
std::string pattern = "[,()] ";
|
|
||||||
for (int i = 0; varnames[i]; i++)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
pattern += " . ";
|
|
||||||
|
|
||||||
pattern += varnames[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern += " [,()]";
|
|
||||||
|
|
||||||
for (; tok; tok = tok->next())
|
for (; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -512,7 +530,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
{
|
{
|
||||||
if (tok->str() == ",")
|
if (tok->str() == ",")
|
||||||
++par;
|
++par;
|
||||||
if (Token::Match(tok, pattern.c_str()))
|
if (Token::Match(tok, "[,()] %varid% [,()]", varid))
|
||||||
{
|
{
|
||||||
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
|
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
|
||||||
if (!ftok)
|
if (!ftok)
|
||||||
|
@ -525,10 +543,18 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
const char *parname = Tokenizer::getParameterName(ftok, par);
|
const char *parname = Tokenizer::getParameterName(ftok, par);
|
||||||
if (! parname)
|
if (! parname)
|
||||||
return "recursive";
|
return "recursive";
|
||||||
|
unsigned int parameterVarid = 0;
|
||||||
|
{
|
||||||
|
const Token *partok = Token::findmatch(ftok, parname);
|
||||||
|
if (partok)
|
||||||
|
parameterVarid = partok->varId();
|
||||||
|
}
|
||||||
|
if (parameterVarid == 0)
|
||||||
|
return "recursive";
|
||||||
// Check if the function deallocates the variable..
|
// Check if the function deallocates the variable..
|
||||||
while (ftok && (ftok->str() != "{"))
|
while (ftok && (ftok->str() != "{"))
|
||||||
ftok = ftok->next();
|
ftok = ftok->next();
|
||||||
Token *func = getcode(ftok->tokAt(1), callstack, parname, alloctype, dealloctype, false, all, sz);
|
Token *func = getcode(ftok->tokAt(1), callstack, parameterVarid, alloctype, dealloctype, false, all, sz);
|
||||||
simplifycode(func, all);
|
simplifycode(func, all);
|
||||||
const Token *func_ = func;
|
const Token *func_ = func;
|
||||||
while (func_ && func_->str() == ";")
|
while (func_ && func_->str() == ";")
|
||||||
|
@ -553,13 +579,8 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz)
|
Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz)
|
||||||
{
|
{
|
||||||
const char *varnames[2];
|
|
||||||
varnames[0] = varname;
|
|
||||||
varnames[1] = 0;
|
|
||||||
std::string varnameStr = varname;
|
|
||||||
|
|
||||||
Token *rethead = 0, *rettail = 0;
|
Token *rethead = 0, *rettail = 0;
|
||||||
#define addtoken(_str) \
|
#define addtoken(_str) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -610,9 +631,9 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (parlevel == 0 && tok->str() == ";")
|
if (parlevel == 0 && tok->str() == ";")
|
||||||
addtoken(";");
|
addtoken(";");
|
||||||
|
|
||||||
if (Token::Match(tok->previous(), std::string("[(;{}] " + varnameStr + " =").c_str()))
|
if (Token::Match(tok->previous(), "[(;{}] %varid% =", varid))
|
||||||
{
|
{
|
||||||
AllocType alloc = getAllocationType(tok->tokAt(2), varname);
|
AllocType alloc = getAllocationType(tok->tokAt(2), varid);
|
||||||
bool realloc = false;
|
bool realloc = false;
|
||||||
|
|
||||||
if (sz > 1 &&
|
if (sz > 1 &&
|
||||||
|
@ -624,7 +645,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
|
|
||||||
if (alloc == No)
|
if (alloc == No)
|
||||||
{
|
{
|
||||||
alloc = getReallocationType(tok->tokAt(2), varname);
|
alloc = getReallocationType(tok->tokAt(2), varid);
|
||||||
if (alloc != No)
|
if (alloc != No)
|
||||||
{
|
{
|
||||||
addtoken("realloc");
|
addtoken("realloc");
|
||||||
|
@ -673,14 +694,14 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (alloc != Many && dealloctype != No && dealloctype != Many && dealloctype != alloc)
|
if (alloc != Many && dealloctype != No && dealloctype != Many && dealloctype != alloc)
|
||||||
{
|
{
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
mismatchAllocDealloc(callstack, varname);
|
mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
|
||||||
callstack.pop_back();
|
callstack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
alloctype = alloc;
|
alloctype = alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (matchFunctionsThatReturnArg(tok->previous(), std::string(varname)))
|
else if (matchFunctionsThatReturnArg(tok->previous(), varid))
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
}
|
}
|
||||||
|
@ -690,13 +711,12 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
{
|
{
|
||||||
// is the pointer in rhs?
|
// is the pointer in rhs?
|
||||||
bool rhs = false;
|
bool rhs = false;
|
||||||
std::string pattern("[=+] " + std::string(varname));
|
|
||||||
for (const Token *tok2 = tok; tok2; tok2 = tok2->next())
|
for (const Token *tok2 = tok; tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
if (tok2->str() == ";")
|
if (tok2->str() == ";")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (Token::Match(tok2, pattern.c_str()))
|
if (Token::Match(tok2, "[=+] %varid%", varid))
|
||||||
{
|
{
|
||||||
rhs = true;
|
rhs = true;
|
||||||
break;
|
break;
|
||||||
|
@ -709,7 +729,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
|
|
||||||
if (Token::Match(tok->previous(), "[;{})=] %var%"))
|
if (Token::Match(tok->previous(), "[;{})=] %var%"))
|
||||||
{
|
{
|
||||||
AllocType dealloc = getDeallocationType(tok, varnames);
|
AllocType dealloc = getDeallocationType(tok, varid);
|
||||||
if (dealloc != No)
|
if (dealloc != No)
|
||||||
{
|
{
|
||||||
addtoken("dealloc");
|
addtoken("dealloc");
|
||||||
|
@ -720,7 +740,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (dealloc != Many && alloctype != No && alloctype != Many && alloctype != dealloc)
|
if (dealloc != Many && alloctype != No && alloctype != Many && alloctype != dealloc)
|
||||||
{
|
{
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
mismatchAllocDealloc(callstack, varname);
|
mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
|
||||||
callstack.pop_back();
|
callstack.pop_back();
|
||||||
}
|
}
|
||||||
dealloctype = dealloc;
|
dealloctype = dealloc;
|
||||||
|
@ -731,20 +751,20 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
// if else switch
|
// if else switch
|
||||||
if (tok->str() == "if")
|
if (tok->str() == "if")
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(tok, std::string("if ( " + varnameStr + " )").c_str()))
|
if (Token::Match(tok, "if ( %varid% )", varid))
|
||||||
{
|
{
|
||||||
addtoken("if(var)");
|
addtoken("if(var)");
|
||||||
|
|
||||||
// Make sure the "use" will not be added
|
// Make sure the "use" will not be added
|
||||||
tok = tok->next()->link();
|
tok = tok->next()->link();
|
||||||
}
|
}
|
||||||
else if (Token::simpleMatch(tok, std::string("if ( " + varnameStr + " == -1 )").c_str()) ||
|
else if (Token::Match(tok, "if ( %varid% == -1 )", varid) ||
|
||||||
Token::simpleMatch(tok, std::string("if ( " + varnameStr + " < 0 )").c_str()))
|
Token::Match(tok, "if ( %varid% < 0 )", varid))
|
||||||
{
|
{
|
||||||
// FIXME: ensure then this variable has int type and uses as file descriptor
|
// FIXME: ensure then this variable has int type and uses as file descriptor
|
||||||
addtoken("if(!var)");
|
addtoken("if(!var)");
|
||||||
}
|
}
|
||||||
else if (Token::simpleMatch(tok, "if (") && notvar(tok->tokAt(2), varnames, true))
|
else if (Token::simpleMatch(tok, "if (") && notvar(tok->tokAt(2), varid, true))
|
||||||
{
|
{
|
||||||
addtoken("if(!var)");
|
addtoken("if(!var)");
|
||||||
}
|
}
|
||||||
|
@ -763,29 +783,27 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (parlevel <= 0)
|
if (parlevel <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (Token::Match(tok2, std::string("close|fclose|closedir ( " + varnameStr + " )").c_str()))
|
if (Token::Match(tok2, "close|fclose|closedir ( %varid% )", varid))
|
||||||
{
|
{
|
||||||
addtoken("dealloc");
|
addtoken("dealloc");
|
||||||
addtoken(";");
|
addtoken(";");
|
||||||
dep = true;
|
dep = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((tok2->str() != ".") &&
|
if (Token::Match(tok2, ". %varid% !!.", varid))
|
||||||
Token::simpleMatch(tok2->next(), varnameStr.c_str()) &&
|
|
||||||
!Token::simpleMatch(tok2->next(), std::string(varnameStr + " .").c_str()))
|
|
||||||
{
|
{
|
||||||
dep = true;
|
dep = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, std::string("if ( ! " + varnameStr + " &&").c_str()))
|
if (Token::Match(tok, "if ( ! %varid% &&", varid))
|
||||||
{
|
{
|
||||||
addtoken("if(!var)");
|
addtoken("if(!var)");
|
||||||
}
|
}
|
||||||
else if (tok->next() &&
|
else if (tok->next() &&
|
||||||
tok->next()->link() &&
|
tok->next()->link() &&
|
||||||
Token::simpleMatch(tok->next()->link()->tokAt(-3), std::string("&& ! " + varnameStr).c_str()))
|
Token::Match(tok->next()->link()->tokAt(-3), "&& ! %varid%", varid))
|
||||||
{
|
{
|
||||||
addtoken("if(!var)");
|
addtoken("if(!var)");
|
||||||
}
|
}
|
||||||
|
@ -823,7 +841,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
{
|
{
|
||||||
addtoken("do");
|
addtoken("do");
|
||||||
}
|
}
|
||||||
if (isloop && notvar(tok, varnames))
|
if (isloop && notvar(tok, varid))
|
||||||
addtoken("!var");
|
addtoken("!var");
|
||||||
|
|
||||||
// continue / break..
|
// continue / break..
|
||||||
|
@ -849,19 +867,19 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
const Token *tok2 = tok->tokAt(5);
|
const Token *tok2 = tok->tokAt(5);
|
||||||
while (tok2 && tok2->str() != ">")
|
while (tok2 && tok2->str() != ">")
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
if (Token::simpleMatch(tok2, ("> ( " + varnameStr + " )").c_str()))
|
if (Token::Match(tok2, "> ( %varid% )", varid))
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
tok = tok2->tokAt(3);
|
tok = tok2->tokAt(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, ("return &| " + varnameStr).c_str()))
|
else if (Token::Match(tok, "return &| %varid%", varid))
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, ("return strcpy|strncpy|memcpy ( " + varnameStr).c_str()))
|
else if (Token::Match(tok, "return strcpy|strncpy|memcpy ( %varid%", varid))
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
|
@ -874,7 +892,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (tok2->str() == ";")
|
if (tok2->str() == ";")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (tok2->str() == varname)
|
if (tok2->varId() == varid)
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
break;
|
break;
|
||||||
|
@ -895,14 +913,14 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assignment..
|
// Assignment..
|
||||||
if (Token::Match(tok, std::string("[)=] " + varnameStr + " [+;)]").c_str()) ||
|
if (Token::Match(tok, "[)=] %varid% [+;)]", varid) ||
|
||||||
Token::Match(tok, std::string(varnameStr + " +=|-=").c_str()) ||
|
Token::Match(tok, "%varid% +=|-=", varid) ||
|
||||||
Token::Match(tok, std::string("+=|<< " + varnameStr + " ;").c_str()) ||
|
Token::Match(tok, "+=|<< %varid% ;", varid) ||
|
||||||
Token::Match(tok, std::string("= strcpy|strcat|memmove|memcpy ( " + varnameStr + " ,").c_str()))
|
Token::Match(tok, "= strcpy|strcat|memmove|memcpy ( %varid% ,", varid))
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok->previous(), std::string("[;{}=(,+-*/] " + varnameStr + " [").c_str()))
|
else if (Token::Match(tok->previous(), "[;{}=(,+-*/] %varid% [", varid))
|
||||||
{
|
{
|
||||||
addtoken("use_");
|
addtoken("use_");
|
||||||
}
|
}
|
||||||
|
@ -926,7 +944,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (parlevel <= 0)
|
if (parlevel <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tok2->str() == varnameStr)
|
if (tok2->varId() == varid)
|
||||||
{
|
{
|
||||||
addtoken("::use");
|
addtoken("::use");
|
||||||
break;
|
break;
|
||||||
|
@ -936,17 +954,16 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype, all, sz);
|
const char *str = call_func(tok, callstack, varid, alloctype, dealloctype, all, sz);
|
||||||
if (str)
|
if (str)
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(tok->tokAt(-2), (varnameStr + " =").c_str()) || std::string(str) != "alloc")
|
if (Token::Match(tok->tokAt(-2), "%varid% =", varid) || std::string(str) != "alloc")
|
||||||
addtoken(str);
|
addtoken(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (getReallocationType(tok, varname) != No &&
|
if (getReallocationType(tok, varid) != No &&
|
||||||
Token::simpleMatch(tok->tokAt(2), varnameStr.c_str())
|
tok->tokAt(2)->varId() == varid)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
addtoken("if");
|
addtoken("if");
|
||||||
addtoken("{");
|
addtoken("{");
|
||||||
|
@ -975,7 +992,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
{
|
{
|
||||||
if (Token::Match(tok2, "[;{]"))
|
if (Token::Match(tok2, "[;{]"))
|
||||||
break;
|
break;
|
||||||
else if (tok2->str() == varname)
|
else if (tok2->varId() == varid)
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
break;
|
break;
|
||||||
|
@ -985,7 +1002,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linux lists..
|
// Linux lists..
|
||||||
if (Token::Match(tok, std::string("[=(,] & " + varnameStr + " [.[,)]").c_str()))
|
if (Token::Match(tok, "[=(,] & %varid% [.[,)]", varid))
|
||||||
{
|
{
|
||||||
addtoken("&use");
|
addtoken("&use");
|
||||||
}
|
}
|
||||||
|
@ -1503,7 +1520,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok, bool &all)
|
||||||
|
|
||||||
|
|
||||||
// Check for memory leaks for a function variable.
|
// Check for memory leaks for a function variable.
|
||||||
void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz)
|
void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string varname, const unsigned int varid, bool classmember, unsigned int sz)
|
||||||
{
|
{
|
||||||
std::list<const Token *> callstack;
|
std::list<const Token *> callstack;
|
||||||
|
|
||||||
|
@ -1514,7 +1531,7 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const char varname
|
||||||
|
|
||||||
const Token *result;
|
const Token *result;
|
||||||
|
|
||||||
Token *tok = getcode(Tok1, callstack, varname, alloctype, dealloctype, classmember, all, sz);
|
Token *tok = getcode(Tok1, callstack, varid, alloctype, dealloctype, classmember, all, sz);
|
||||||
//tok->printOut((std::string("Checkmemoryleak: getcode result for: ") + varname).c_str());
|
//tok->printOut((std::string("Checkmemoryleak: getcode result for: ") + varname).c_str());
|
||||||
|
|
||||||
// Simplify the code and check if freed memory is used..
|
// Simplify the code and check if freed memory is used..
|
||||||
|
@ -1553,7 +1570,7 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const char varname
|
||||||
|
|
||||||
if (_settings->_debug)
|
if (_settings->_debug)
|
||||||
{
|
{
|
||||||
tok->printOut((std::string("Checkmemoryleak: simplifycode result for: ") + varname).c_str());
|
tok->printOut(("Checkmemoryleak: simplifycode result for: " + varname).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the variable is not allocated at all => no memory leak
|
// If the variable is not allocated at all => no memory leak
|
||||||
|
@ -1715,19 +1732,20 @@ void CheckMemoryLeakInFunction::check()
|
||||||
|
|
||||||
if (Token::Match(tok, "[{};] %type% * const| %var% [;=]"))
|
if (Token::Match(tok, "[{};] %type% * const| %var% [;=]"))
|
||||||
{
|
{
|
||||||
const int varname_tok = (tok->tokAt(3)->str() != "const" ? 3 : 4);
|
const Token *vartok = tok->tokAt(tok->tokAt(3)->str() != "const" ? 3 : 4);
|
||||||
checkScope(tok->next(), tok->strAt(varname_tok), classmember, sz);
|
checkScope(tok->next(), vartok->str(), vartok->varId(), classmember, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "[{};] %type% %type% * const| %var% [;=]"))
|
else if (Token::Match(tok, "[{};] %type% %type% * const| %var% [;=]"))
|
||||||
{
|
{
|
||||||
const int varname_tok = (tok->tokAt(4)->str() != "const" ? 4 : 5);
|
const Token *vartok = tok->tokAt(tok->tokAt(4)->str() != "const" ? 4 : 5);
|
||||||
checkScope(tok->next(), tok->strAt(varname_tok), classmember, sz);
|
checkScope(tok->next(), vartok->str(), vartok->varId(), classmember, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "[{};] int %var% [;=]"))
|
else if (Token::Match(tok, "[{};] int %var% [;=]"))
|
||||||
{
|
{
|
||||||
checkScope(tok->next(), tok->strAt(2), classmember, sz);
|
const Token *vartok = tok->tokAt(2);
|
||||||
|
checkScope(tok->next(), vartok->str(), vartok->varId(), classmember, sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1876,7 +1894,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), varname);
|
AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3), 0);
|
||||||
if (alloc != CheckMemoryLeak::No)
|
if (alloc != CheckMemoryLeak::No)
|
||||||
{
|
{
|
||||||
if (Alloc != No && Alloc != alloc)
|
if (Alloc != No && Alloc != alloc)
|
||||||
|
|
|
@ -85,22 +85,33 @@ public:
|
||||||
/** What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
|
/** What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
|
||||||
enum AllocType { No, Malloc, gMalloc, New, NewArray, File, Fd, Pipe, Dir, Many };
|
enum AllocType { No, Malloc, gMalloc, New, NewArray, File, Fd, Pipe, Dir, Many };
|
||||||
|
|
||||||
void memoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all);
|
void memoryLeak(const Token *tok, const std::string varname, AllocType alloctype, bool all);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get type of deallocation at given position
|
* Get type of deallocation at given position
|
||||||
|
* @param tok position
|
||||||
|
* @param varnames variable names
|
||||||
|
* @return type of deallocation
|
||||||
*/
|
*/
|
||||||
AllocType getDeallocationType(const Token *tok, const char *varnames[]);
|
AllocType getDeallocationType(const Token *tok, const char *varnames[]) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get type of deallocation at given position
|
||||||
|
* @param tok position
|
||||||
|
* @param varname variable name
|
||||||
|
* @return type of deallocation
|
||||||
|
*/
|
||||||
|
AllocType getDeallocationType(const Token *tok, const unsigned int varid) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get type of allocation at given position
|
* Get type of allocation at given position
|
||||||
*/
|
*/
|
||||||
AllocType getAllocationType(const Token *tok2, const char varname[]) const;
|
AllocType getAllocationType(const Token *tok2, const unsigned int varid) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get type of reallocation at given position
|
* Get type of reallocation at given position
|
||||||
*/
|
*/
|
||||||
AllocType getReallocationType(const Token *tok2, const char varname[]);
|
AllocType getReallocationType(const Token *tok2, const unsigned int varid) const;
|
||||||
|
|
||||||
bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const;
|
bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const;
|
||||||
|
|
||||||
|
@ -157,16 +168,16 @@ public:
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool matchFunctionsThatReturnArg(const Token *tok, const std::string &varname);
|
bool matchFunctionsThatReturnArg(const Token *tok, const unsigned int varid) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there is a "!var" match inside a condition
|
* Check if there is a "!var" match inside a condition
|
||||||
* @param tok first token to match
|
* @param tok first token to match
|
||||||
* @param varnames the varname
|
* @param varname the varname
|
||||||
* @param endpar if this is true the "!var" must be followed by ")"
|
* @param endpar if this is true the "!var" must be followed by ")"
|
||||||
* @return true if match
|
* @return true if match
|
||||||
*/
|
*/
|
||||||
bool notvar(const Token *tok, const char *varnames[], bool endpar = false);
|
bool notvar(const Token *tok, const unsigned int varid, bool endpar = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspect a function call. the call_func and getcode are recursive
|
* Inspect a function call. the call_func and getcode are recursive
|
||||||
|
@ -187,7 +198,7 @@ private:
|
||||||
* - "callfunc"
|
* - "callfunc"
|
||||||
* - "&use"
|
* - "&use"
|
||||||
*/
|
*/
|
||||||
const char * call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz);
|
const char * call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract a new tokens list that is easier to parse than the "_tokenizer->tokens()", the
|
* Extract a new tokens list that is easier to parse than the "_tokenizer->tokens()", the
|
||||||
|
@ -221,7 +232,7 @@ private:
|
||||||
* - goto : corresponds to a "goto"
|
* - goto : corresponds to a "goto"
|
||||||
* - return : corresponds to a "return"
|
* - return : corresponds to a "return"
|
||||||
*/
|
*/
|
||||||
Token *getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz);
|
Token *getcode(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplify code e.g. by replacing empty "{ }" with ";"
|
* Simplify code e.g. by replacing empty "{ }" with ";"
|
||||||
|
@ -237,7 +248,7 @@ private:
|
||||||
* @param classmember is the scope inside a class member function
|
* @param classmember is the scope inside a class member function
|
||||||
* @param sz size of type.. if the variable is a "int *" then sz should be "sizeof(int)"
|
* @param sz size of type.. if the variable is a "int *" then sz should be "sizeof(int)"
|
||||||
*/
|
*/
|
||||||
void checkScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz);
|
void checkScope(const Token *Tok1, const std::string varname, const unsigned int varid, bool classmember, unsigned int sz);
|
||||||
|
|
||||||
void getErrorMessages()
|
void getErrorMessages()
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@ private:
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
tokenizer.setVarId();
|
||||||
|
|
||||||
return ((const CheckMemoryLeak *)0)->functionReturnType(tokenizer.tokens());
|
return ((const CheckMemoryLeak *)0)->functionReturnType(tokenizer.tokens());
|
||||||
}
|
}
|
||||||
|
@ -1725,6 +1726,9 @@ private:
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
tokenizer.setVarId();
|
||||||
|
|
||||||
|
const unsigned int varid(Token::findmatch(tokenizer.tokens(), varname)->varId());
|
||||||
|
|
||||||
// getcode..
|
// getcode..
|
||||||
CheckMemoryLeakInFunction checkMemoryLeak;
|
CheckMemoryLeakInFunction checkMemoryLeak;
|
||||||
|
@ -1732,7 +1736,7 @@ private:
|
||||||
CheckMemoryLeak::AllocType allocType, deallocType;
|
CheckMemoryLeak::AllocType allocType, deallocType;
|
||||||
allocType = deallocType = CheckMemoryLeak::No;
|
allocType = deallocType = CheckMemoryLeak::No;
|
||||||
bool all = false;
|
bool all = false;
|
||||||
Token *tokens = checkMemoryLeak.getcode(tokenizer.tokens(), callstack, varname, allocType, deallocType, false, all, 1);
|
Token *tokens = checkMemoryLeak.getcode(tokenizer.tokens(), callstack, varid, allocType, deallocType, false, all, 1);
|
||||||
|
|
||||||
// stringify..
|
// stringify..
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
@ -1746,8 +1750,8 @@ private:
|
||||||
|
|
||||||
void realloc6()
|
void realloc6()
|
||||||
{
|
{
|
||||||
ASSERT_EQUALS(";;realloc;;", getcode(";buf=realloc(buf,100);", "buf"));
|
ASSERT_EQUALS(";;realloc;;", getcode("char *buf; buf=realloc(buf,100);", "buf"));
|
||||||
ASSERT_EQUALS(";;alloc;", getcode(";buf=realloc(0,100);", "buf"));
|
ASSERT_EQUALS(";;alloc;", getcode("char *buf; buf=realloc(0,100);", "buf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign()
|
void assign()
|
||||||
|
@ -1818,7 +1822,7 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
" free(p);\n"
|
" free(p);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
TODO_ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cast1()
|
void cast1()
|
||||||
|
|
Loading…
Reference in New Issue