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:
PKEuS 2012-03-16 19:52:18 +01:00
parent 2757229064
commit fb4709f1be
2 changed files with 64 additions and 79 deletions

View File

@ -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..

View File

@ -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;