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;
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
static const char * const mallocfunc[] = {"malloc",
"calloc",
"strdup",
"strndup",
"kmalloc",
"kzalloc",
"kcalloc",
0
};
for (unsigned int i = 0; mallocfunc[i]; i++) {
static const char * const mallocfunc[] = {
"malloc",
"calloc",
"strdup",
"strndup",
"kmalloc",
"kzalloc",
"kcalloc"
};
for (unsigned int i = 0; i < sizeof(mallocfunc)/sizeof(*mallocfunc); i++) {
if (tok2->str() == mallocfunc[i])
return Malloc;
}
@ -137,20 +137,20 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
return Malloc;
// Does tok2 point on "g_malloc", "g_strdup", ..
static const char * const gmallocfunc[] = {"g_new",
"g_new0",
"g_try_new",
"g_try_new0",
"g_malloc",
"g_malloc0",
"g_try_malloc",
"g_try_malloc0",
"g_strdup",
"g_strndup",
"g_strdup_printf",
0
};
for (unsigned int i = 0; gmallocfunc[i]; i++) {
static const char * const gmallocfunc[] = {
"g_new",
"g_new0",
"g_try_new",
"g_try_new0",
"g_malloc",
"g_malloc0",
"g_try_malloc",
"g_try_malloc0",
"g_strdup",
"g_strndup",
"g_strdup_printf"
};
for (unsigned int i = 0; i < sizeof(gmallocfunc)/sizeof(*gmallocfunc); i++) {
if (tok2->str() == gmallocfunc[i])
return gMalloc;
}
@ -640,9 +640,12 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
}
// is the varid a parameter?
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
if (tok2->str() == "(" || tok2->str() == ")")
break;
for (const Token *tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
if (tok2->str() == "(") {
tok2 = tok2->nextArgument();
if (!tok2)
break;
}
if (tok2->varId() == varid) {
if (tok->strAt(-1) == ".")
return "use";
@ -1545,7 +1548,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
}
while (innerIndentlevel == 0 && Token::Match(tok3, "[{};] if|ifv|else { continue ; }")) {
tok3->deleteNext(5);
if (Token::simpleMatch(tok3->next(), "else"))
if (tok3->strAt(1) == "else")
tok3->deleteNext();
}
}
@ -1667,7 +1670,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
else if (Token::Match(tok2, "[;{}] if { dealloc|assign|use ; return ; }") &&
!Token::findmatch(tok, "if {| alloc ;")) {
tok2->deleteNext(7);
if (Token::simpleMatch(tok2->next(), "else"))
if (tok2->strAt(1) == "else")
tok2->deleteNext();
done = false;
}
@ -1722,7 +1725,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
// Reduce "if* ;"..
if (Token::Match(tok2->next(), "if(var)|if(!var)|ifv ;")) {
// Followed by else..
if (Token::simpleMatch(tok2->tokAt(3), "else")) {
if (tok2->strAt(3) == "else") {
tok2 = tok2->next();
if (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:
// 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()
{
std::list<Scope>::const_iterator scope;
@ -2207,34 +2216,15 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
if (scope->type != Scope::eFunction)
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
unsigned int indentlevel = 1;
for (tok = tok->next(); tok; tok = tok->next()) {
if (tok->str() == "{")
++indentlevel;
else if (tok->str() == "}") {
--indentlevel;
if (indentlevel == 0)
break;
}
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (tok->varId() > 0 &&
Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any%") &&
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
if (Token::findmatch(startOfFunction, "%var% = %varid% ;", tok->varId()) ||
Token::findmatch(startOfFunction, "[{};] %varid% = %var% [;=]", tok->varId()))
if (Token::findmatch(scope->classStart, "%var% = %varid% ;", tok->varId()) ||
Token::findmatch(scope->classStart, "[{};] %varid% = %var% [;=]", tok->varId()))
continue;
const Token* tokEndRealloc = tok->linkAt(3);
@ -2249,11 +2239,11 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
memleakUponReallocFailureError(tok, tok->str());
} else if (tok->next()->varId() > 0 &&
(Token::Match(tok, "* %var% = realloc|g_try_realloc ( * %var% , %any%") &&
tok->next()->varId() == tok->tokAt(6)->varId())&&
parameterVarIds.find(tok->next()->varId()) == parameterVarIds.end()) {
tok->next()->varId() == tok->tokAt(6)->varId()) &&
isNoArgument(symbolDatabase, tok->next()->varId())) {
// Check that another copy of the pointer wasn't saved earlier in the function
if (Token::findmatch(startOfFunction, "%var% = * %varid% ;", tok->next()->varId()) ||
Token::findmatch(startOfFunction, "[{};] * %varid% = %var% [;=]", tok->next()->varId()))
if (Token::findmatch(scope->classStart, "%var% = * %varid% ;", tok->next()->varId()) ||
Token::findmatch(scope->classStart, "[{};] * %varid% = %var% [;=]", tok->next()->varId()))
continue;
const Token* tokEndRealloc = tok->linkAt(4);
@ -2445,40 +2435,34 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
// Inspect member functions
std::list<Function>::const_iterator 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 destructor = func->type == Function::eDestructor;
unsigned int indent = 0;
bool initlist = false;
for (const Token *tok = functionToken; tok; tok = tok->next()) {
if (tok->str() == "{")
++indent;
else if (tok->str() == "}") {
if (indent <= 1)
break;
--indent;
} else if (indent == 0 && Token::simpleMatch(tok, ") :"))
initlist = true;
else if (initlist || indent > 0) {
if (indent == 0) {
bool body = false;
bool initlist = func->token->linkAt(1)->strAt(1) == ":";
const Token *end = func->start->link();
for (const Token *tok = func->token; tok != end; tok = tok->next()) {
if (tok == func->start)
body = true;
else if (initlist || body) {
if (!body) {
if (!Token::Match(tok, (":|, " + varname + " (").c_str()))
continue;
}
// Allocate..
if (indent == 0 || Token::simpleMatch(tok, (varname + " =").c_str())) {
if (!body || Token::simpleMatch(tok, (varname + " =").c_str())) {
// var1 = var2 = ...
// bail out
if (Token::simpleMatch(tok->previous(), "="))
if (tok->strAt(-1) == "=")
return;
// Foo::var1 = ..
// bail out when not same class
if (Token::simpleMatch(tok->previous(), "::") &&
if (tok->strAt(-1) == "::" &&
tok->strAt(-2) != scope->className)
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 (constructor)
allocInConstructor = true;
@ -2497,7 +2481,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
}
}
if (indent == 0)
if (!body)
continue;
// 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);
/** parse tokens to see what functions are "noreturn" */
void parse_noreturn();
private:
/** Report all possible errors (for the --errorlist) */
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
CheckMemoryLeakInFunction c(0, settings, e);
@ -336,9 +340,6 @@ public:
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" */
std::set<std::string> noreturn;