Refactorizations in checkmemoryleak:
- Replaced two indendation counters and one variable storage by symboldatabase functions - Removed zero-element at end of two static arrays - More accurate algorithm for finding a parameter by varid - Replaced some simple tokens by direct string comparision - Made some functions in checkmemoryleak.h private to improve encapsulation
This commit is contained in:
parent
2757229064
commit
fb4709f1be
|
@ -118,16 +118,16 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
return No;
|
return No;
|
||||||
|
|
||||||
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
|
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
|
||||||
static const char * const mallocfunc[] = {"malloc",
|
static const char * const mallocfunc[] = {
|
||||||
|
"malloc",
|
||||||
"calloc",
|
"calloc",
|
||||||
"strdup",
|
"strdup",
|
||||||
"strndup",
|
"strndup",
|
||||||
"kmalloc",
|
"kmalloc",
|
||||||
"kzalloc",
|
"kzalloc",
|
||||||
"kcalloc",
|
"kcalloc"
|
||||||
0
|
|
||||||
};
|
};
|
||||||
for (unsigned int i = 0; mallocfunc[i]; i++) {
|
for (unsigned int i = 0; i < sizeof(mallocfunc)/sizeof(*mallocfunc); i++) {
|
||||||
if (tok2->str() == mallocfunc[i])
|
if (tok2->str() == mallocfunc[i])
|
||||||
return Malloc;
|
return Malloc;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,8 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
return Malloc;
|
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",
|
||||||
"g_try_new",
|
"g_try_new",
|
||||||
"g_try_new0",
|
"g_try_new0",
|
||||||
|
@ -147,10 +148,9 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
"g_try_malloc0",
|
"g_try_malloc0",
|
||||||
"g_strdup",
|
"g_strdup",
|
||||||
"g_strndup",
|
"g_strndup",
|
||||||
"g_strdup_printf",
|
"g_strdup_printf"
|
||||||
0
|
|
||||||
};
|
};
|
||||||
for (unsigned int i = 0; gmallocfunc[i]; i++) {
|
for (unsigned int i = 0; i < sizeof(gmallocfunc)/sizeof(*gmallocfunc); i++) {
|
||||||
if (tok2->str() == gmallocfunc[i])
|
if (tok2->str() == gmallocfunc[i])
|
||||||
return gMalloc;
|
return gMalloc;
|
||||||
}
|
}
|
||||||
|
@ -640,9 +640,12 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
}
|
}
|
||||||
|
|
||||||
// is the varid a parameter?
|
// is the varid a parameter?
|
||||||
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
|
for (const Token *tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
|
||||||
if (tok2->str() == "(" || tok2->str() == ")")
|
if (tok2->str() == "(") {
|
||||||
|
tok2 = tok2->nextArgument();
|
||||||
|
if (!tok2)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (tok2->varId() == varid) {
|
if (tok2->varId() == varid) {
|
||||||
if (tok->strAt(-1) == ".")
|
if (tok->strAt(-1) == ".")
|
||||||
return "use";
|
return "use";
|
||||||
|
@ -1545,7 +1548,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
|
||||||
}
|
}
|
||||||
while (innerIndentlevel == 0 && Token::Match(tok3, "[{};] if|ifv|else { continue ; }")) {
|
while (innerIndentlevel == 0 && Token::Match(tok3, "[{};] if|ifv|else { continue ; }")) {
|
||||||
tok3->deleteNext(5);
|
tok3->deleteNext(5);
|
||||||
if (Token::simpleMatch(tok3->next(), "else"))
|
if (tok3->strAt(1) == "else")
|
||||||
tok3->deleteNext();
|
tok3->deleteNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1667,7 +1670,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
|
||||||
else if (Token::Match(tok2, "[;{}] if { dealloc|assign|use ; return ; }") &&
|
else if (Token::Match(tok2, "[;{}] if { dealloc|assign|use ; return ; }") &&
|
||||||
!Token::findmatch(tok, "if {| alloc ;")) {
|
!Token::findmatch(tok, "if {| alloc ;")) {
|
||||||
tok2->deleteNext(7);
|
tok2->deleteNext(7);
|
||||||
if (Token::simpleMatch(tok2->next(), "else"))
|
if (tok2->strAt(1) == "else")
|
||||||
tok2->deleteNext();
|
tok2->deleteNext();
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
@ -1722,7 +1725,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
|
||||||
// Reduce "if* ;"..
|
// Reduce "if* ;"..
|
||||||
if (Token::Match(tok2->next(), "if(var)|if(!var)|ifv ;")) {
|
if (Token::Match(tok2->next(), "if(var)|if(!var)|ifv ;")) {
|
||||||
// Followed by else..
|
// Followed by else..
|
||||||
if (Token::simpleMatch(tok2->tokAt(3), "else")) {
|
if (tok2->strAt(3) == "else") {
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
if (tok2->str() == "if(var)")
|
if (tok2->str() == "if(var)")
|
||||||
tok2->str("if(!var)");
|
tok2->str("if(!var)");
|
||||||
|
@ -2198,6 +2201,12 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string
|
||||||
// allocate the requested memory:
|
// allocate the requested memory:
|
||||||
// a = malloc(10); a = realloc(a, 100);
|
// a = malloc(10); a = realloc(a, 100);
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
static bool isNoArgument(const SymbolDatabase* symbolDatabase, unsigned int varid)
|
||||||
|
{
|
||||||
|
const Variable* var = symbolDatabase->getVariableFromVarId(varid);
|
||||||
|
return var && !var->isArgument();
|
||||||
|
}
|
||||||
|
|
||||||
void CheckMemoryLeakInFunction::checkReallocUsage()
|
void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
{
|
{
|
||||||
std::list<Scope>::const_iterator scope;
|
std::list<Scope>::const_iterator scope;
|
||||||
|
@ -2207,34 +2216,15 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
if (scope->type != Scope::eFunction)
|
if (scope->type != Scope::eFunction)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Record the varid's of the function parameters
|
|
||||||
std::set<unsigned int> parameterVarIds;
|
|
||||||
for (const Token *tok2 = scope->classDef->next(); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
|
|
||||||
if (tok2->varId() != 0)
|
|
||||||
parameterVarIds.insert(tok2->varId());
|
|
||||||
}
|
|
||||||
|
|
||||||
const Token *tok = scope->classStart;
|
|
||||||
const Token *startOfFunction = tok;
|
|
||||||
|
|
||||||
// Search for the "var = realloc(var, 100" pattern within this function
|
// Search for the "var = realloc(var, 100" pattern within this function
|
||||||
unsigned int indentlevel = 1;
|
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
||||||
for (tok = tok->next(); tok; tok = tok->next()) {
|
|
||||||
if (tok->str() == "{")
|
|
||||||
++indentlevel;
|
|
||||||
else if (tok->str() == "}") {
|
|
||||||
--indentlevel;
|
|
||||||
if (indentlevel == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->varId() > 0 &&
|
if (tok->varId() > 0 &&
|
||||||
Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any%") &&
|
Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any%") &&
|
||||||
tok->varId() == tok->tokAt(4)->varId() &&
|
tok->varId() == tok->tokAt(4)->varId() &&
|
||||||
parameterVarIds.find(tok->varId()) == parameterVarIds.end()) {
|
isNoArgument(symbolDatabase, tok->varId())) {
|
||||||
// Check that another copy of the pointer wasn't saved earlier in the function
|
// Check that another copy of the pointer wasn't saved earlier in the function
|
||||||
if (Token::findmatch(startOfFunction, "%var% = %varid% ;", tok->varId()) ||
|
if (Token::findmatch(scope->classStart, "%var% = %varid% ;", tok->varId()) ||
|
||||||
Token::findmatch(startOfFunction, "[{};] %varid% = %var% [;=]", tok->varId()))
|
Token::findmatch(scope->classStart, "[{};] %varid% = %var% [;=]", tok->varId()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Token* tokEndRealloc = tok->linkAt(3);
|
const Token* tokEndRealloc = tok->linkAt(3);
|
||||||
|
@ -2249,11 +2239,11 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
memleakUponReallocFailureError(tok, tok->str());
|
memleakUponReallocFailureError(tok, tok->str());
|
||||||
} else if (tok->next()->varId() > 0 &&
|
} else if (tok->next()->varId() > 0 &&
|
||||||
(Token::Match(tok, "* %var% = realloc|g_try_realloc ( * %var% , %any%") &&
|
(Token::Match(tok, "* %var% = realloc|g_try_realloc ( * %var% , %any%") &&
|
||||||
tok->next()->varId() == tok->tokAt(6)->varId())&&
|
tok->next()->varId() == tok->tokAt(6)->varId()) &&
|
||||||
parameterVarIds.find(tok->next()->varId()) == parameterVarIds.end()) {
|
isNoArgument(symbolDatabase, tok->next()->varId())) {
|
||||||
// Check that another copy of the pointer wasn't saved earlier in the function
|
// Check that another copy of the pointer wasn't saved earlier in the function
|
||||||
if (Token::findmatch(startOfFunction, "%var% = * %varid% ;", tok->next()->varId()) ||
|
if (Token::findmatch(scope->classStart, "%var% = * %varid% ;", tok->next()->varId()) ||
|
||||||
Token::findmatch(startOfFunction, "[{};] * %varid% = %var% [;=]", tok->next()->varId()))
|
Token::findmatch(scope->classStart, "[{};] * %varid% = %var% [;=]", tok->next()->varId()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Token* tokEndRealloc = tok->linkAt(4);
|
const Token* tokEndRealloc = tok->linkAt(4);
|
||||||
|
@ -2445,40 +2435,34 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
|
||||||
// Inspect member functions
|
// Inspect member functions
|
||||||
std::list<Function>::const_iterator func;
|
std::list<Function>::const_iterator func;
|
||||||
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
|
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
|
||||||
const Token *functionToken = func->token;
|
|
||||||
const bool constructor = func->type == Function::eConstructor;
|
const bool constructor = func->type == Function::eConstructor;
|
||||||
const bool destructor = func->type == Function::eDestructor;
|
const bool destructor = func->type == Function::eDestructor;
|
||||||
unsigned int indent = 0;
|
bool body = false;
|
||||||
bool initlist = false;
|
bool initlist = func->token->linkAt(1)->strAt(1) == ":";
|
||||||
for (const Token *tok = functionToken; tok; tok = tok->next()) {
|
const Token *end = func->start->link();
|
||||||
if (tok->str() == "{")
|
for (const Token *tok = func->token; tok != end; tok = tok->next()) {
|
||||||
++indent;
|
if (tok == func->start)
|
||||||
else if (tok->str() == "}") {
|
body = true;
|
||||||
if (indent <= 1)
|
else if (initlist || body) {
|
||||||
break;
|
if (!body) {
|
||||||
--indent;
|
|
||||||
} else if (indent == 0 && Token::simpleMatch(tok, ") :"))
|
|
||||||
initlist = true;
|
|
||||||
else if (initlist || indent > 0) {
|
|
||||||
if (indent == 0) {
|
|
||||||
if (!Token::Match(tok, (":|, " + varname + " (").c_str()))
|
if (!Token::Match(tok, (":|, " + varname + " (").c_str()))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate..
|
// Allocate..
|
||||||
if (indent == 0 || Token::simpleMatch(tok, (varname + " =").c_str())) {
|
if (!body || Token::simpleMatch(tok, (varname + " =").c_str())) {
|
||||||
// var1 = var2 = ...
|
// var1 = var2 = ...
|
||||||
// bail out
|
// bail out
|
||||||
if (Token::simpleMatch(tok->previous(), "="))
|
if (tok->strAt(-1) == "=")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Foo::var1 = ..
|
// Foo::var1 = ..
|
||||||
// bail out when not same class
|
// bail out when not same class
|
||||||
if (Token::simpleMatch(tok->previous(), "::") &&
|
if (tok->strAt(-1) == "::" &&
|
||||||
tok->strAt(-2) != scope->className)
|
tok->strAt(-2) != scope->className)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3), 0);
|
AllocType alloc = getAllocationType(tok->tokAt(body ? 2 : 3), 0);
|
||||||
if (alloc != CheckMemoryLeak::No) {
|
if (alloc != CheckMemoryLeak::No) {
|
||||||
if (constructor)
|
if (constructor)
|
||||||
allocInConstructor = true;
|
allocInConstructor = true;
|
||||||
|
@ -2497,7 +2481,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indent == 0)
|
if (!body)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Deallocate..
|
// Deallocate..
|
||||||
|
|
|
@ -305,6 +305,10 @@ public:
|
||||||
*/
|
*/
|
||||||
void checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
|
void checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
|
||||||
|
|
||||||
|
/** parse tokens to see what functions are "noreturn" */
|
||||||
|
void parse_noreturn();
|
||||||
|
|
||||||
|
private:
|
||||||
/** Report all possible errors (for the --errorlist) */
|
/** Report all possible errors (for the --errorlist) */
|
||||||
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
|
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
|
||||||
CheckMemoryLeakInFunction c(0, settings, e);
|
CheckMemoryLeakInFunction c(0, settings, e);
|
||||||
|
@ -336,9 +340,6 @@ public:
|
||||||
return "Is there any allocated memory when a function goes out of scope";
|
return "Is there any allocated memory when a function goes out of scope";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** parse tokens to see what functions are "noreturn" */
|
|
||||||
void parse_noreturn();
|
|
||||||
|
|
||||||
/** Function names for functions that are "noreturn" */
|
/** Function names for functions that are "noreturn" */
|
||||||
std::set<std::string> noreturn;
|
std::set<std::string> noreturn;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue