Memory leaks: Use varid instead of varname

This commit is contained in:
Daniel Marjamäki 2009-08-19 19:42:07 +02:00
parent 2ca5caab28
commit 8b46172bcf
3 changed files with 142 additions and 109 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 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)

View File

@ -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()
{ {

View File

@ -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()