Memory leaks: Refactoring to use Tokenizer::FindClassFunction. Enabled test case, the memory leak is now detected

This commit is contained in:
Daniel Marjamäki 2009-03-14 18:21:37 +01:00
parent 01c39daa13
commit 02df14ec37
3 changed files with 59 additions and 87 deletions

View File

@ -1447,122 +1447,94 @@ void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_ParseClass(const Token *
if (tok->isName() || Token::Match(tok, "[;}]")) if (tok->isName() || Token::Match(tok, "[;}]"))
{ {
if (_settings._showAll || !isclass(tok->tokAt(1))) if (_settings._showAll || !isclass(tok->tokAt(1)))
CheckMemoryLeak_ClassMembers_Variable(classname, tok->tokAt(3)); CheckMemoryLeak_ClassMembers_Variable(classname.back(), tok->tokAt(3));
} }
} }
} }
} }
void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_Variable(const std::vector<const char *> &classname, const Token *tokVarname) void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_Variable(const char classname[], const Token *tokVarname)
{ {
const char *varname = tokVarname->strAt(0); const char *varname = tokVarname->strAt(0);
// Function pattern.. Check if member function
std::ostringstream fpattern;
for (unsigned int i = 0; i < classname.size(); i++)
{
fpattern << classname[i] << " :: ";
}
fpattern << "%var% (";
// Destructor pattern.. Check if class destructor..
std::ostringstream destructor;
for (unsigned int i = 0; i < classname.size(); i++)
{
destructor << classname[i] << " :: ";
}
destructor << "~ " << classname.back() << " (";
// Pattern used in member function. "Var = ..."
std::ostringstream varname_eq;
varname_eq << varname << " =";
// Full variable name..
std::ostringstream FullVariableName;
for (unsigned int i = 0; i < classname.size(); i++)
FullVariableName << classname[i] << "::";
FullVariableName << varname;
// Check if member variable has been allocated and deallocated.. // Check if member variable has been allocated and deallocated..
AllocType Alloc = No; AllocType Alloc = No;
AllocType Dealloc = No; AllocType Dealloc = No;
// Loop through all tokens. Inspect member functions // Loop through all tokens. Inspect member functions
bool memberfunction = false; int indent_ = 0;
int indentlevel = 0; const Token *functionToken = Tokenizer::FindClassFunction(_tokenizer->tokens(), classname, "~| %var%", indent_);
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) while (functionToken)
{ {
if (tok->str() == "{") int indent = 0;
++indentlevel; for (const Token *tok = functionToken; tok; tok = tok->next())
else if (tok->str() == "}")
--indentlevel;
// Set the 'memberfunction' variable..
if (indentlevel == 0)
{ {
if (Token::Match(tok, "[;}]")) if (tok->str() == "{")
memberfunction = false; ++indent;
else if (Token::Match(tok, fpattern.str().c_str()) || Token::Match(tok, destructor.str().c_str())) else if (tok->str() == "}")
memberfunction = true;
}
// Parse member function..
if (indentlevel > 0 && memberfunction)
{
// Allocate..
if (Token::Match(tok, varname_eq.str().c_str()))
{ {
AllocType alloc = GetAllocationType(tok->tokAt(2)); --indent;
if (alloc != No) if (indent <= 0)
break;
}
else if (indent > 0)
{
// Allocate..
if (Token::Match(tok, (std::string(varname) + " =").c_str()))
{ {
if (Alloc != No && Alloc != alloc) AllocType alloc = GetAllocationType(tok->tokAt(2));
alloc = Many; if (alloc != No)
{
if (Alloc != No && Alloc != alloc)
alloc = Many;
std::list<const Token *> callstack;
if (alloc != Many && Dealloc != No && Dealloc != Many && Dealloc != alloc)
{
callstack.push_back(tok);
_errorLogger->mismatchAllocDealloc(_tokenizer, callstack, (std::string(classname) + "::" + varname).c_str());
callstack.pop_back();
}
Alloc = alloc;
}
}
// Deallocate..
const char *varnames[3] = { "var", 0, 0 };
varnames[0] = varname;
AllocType dealloc = GetDeallocationType(tok, varnames);
if (dealloc == No)
{
varnames[0] = "this";
varnames[1] = varname;
dealloc = GetDeallocationType(tok, varnames);
}
if (dealloc != No)
{
if (Dealloc != No && Dealloc != dealloc)
dealloc = Many;
std::list<const Token *> callstack; std::list<const Token *> callstack;
if (alloc != Many && Dealloc != No && Dealloc != Many && Dealloc != alloc) if (dealloc != Many && Alloc != No && Alloc != Many && Alloc != dealloc)
{ {
callstack.push_back(tok); callstack.push_back(tok);
_errorLogger->mismatchAllocDealloc(_tokenizer, callstack, FullVariableName.str()); _errorLogger->mismatchAllocDealloc(_tokenizer, callstack, (std::string(classname) + "::" + varname).c_str());
callstack.pop_back(); callstack.pop_back();
} }
Alloc = alloc; Dealloc = dealloc;
}
}
// Deallocate..
const char *varnames[3] = { "var", 0, 0 };
varnames[0] = varname;
AllocType dealloc = GetDeallocationType(tok, varnames);
if (dealloc == No)
{
varnames[0] = "this";
varnames[1] = varname;
dealloc = GetDeallocationType(tok, varnames);
}
if (dealloc != No)
{
if (Dealloc != No && Dealloc != dealloc)
dealloc = Many;
std::list<const Token *> callstack;
if (dealloc != Many && Alloc != No && Alloc != Many && Alloc != dealloc)
{
callstack.push_back(tok);
_errorLogger->mismatchAllocDealloc(_tokenizer, callstack, FullVariableName.str());
callstack.pop_back();
} }
Dealloc = dealloc;
} }
} }
functionToken = Tokenizer::FindClassFunction(functionToken->next(), classname, "~| %var%", indent_);
} }
if (Alloc != No && Dealloc == No) if (Alloc != No && Dealloc == No)
{ {
MemoryLeak(tokVarname, FullVariableName.str().c_str(), Alloc, true); MemoryLeak(tokVarname, (std::string(classname) + "::" + varname).c_str(), Alloc, true);
} }
} }

View File

@ -58,7 +58,7 @@ private:
} }
}; };
void CheckMemoryLeak_ClassMembers_Variable(const std::vector<const char *> &classname, const Token *tokVarname); void CheckMemoryLeak_ClassMembers_Variable(const char classname[], const Token *tokVarname);
void CheckMemoryLeak_ClassMembers_ParseClass(const Token *tok1, std::vector<const char *> &classname); void CheckMemoryLeak_ClassMembers_ParseClass(const Token *tok1, std::vector<const char *> &classname);
void CheckMemoryLeak_ClassMembers(); void CheckMemoryLeak_ClassMembers();
void CheckMemoryLeak_InFunction(); void CheckMemoryLeak_InFunction();

View File

@ -152,7 +152,7 @@ private:
TEST_CASE(class7); TEST_CASE(class7);
TEST_CASE(class8); TEST_CASE(class8);
TEST_CASE(class9); TEST_CASE(class9);
// TODO TEST_CASE(class10); TEST_CASE(class10);
// TODO TEST_CASE(class11); // TODO TEST_CASE(class11);
TEST_CASE(throw1); TEST_CASE(throw1);
@ -1525,7 +1525,7 @@ private:
" int * p;\n" " int * p;\n"
" A() { p = new int; }\n" " A() { p = new int; }\n"
"};\n", true); "};\n", true);
ASSERT_EQUALS("memory leak", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (all) Memory leak: A::p\n", errout.str());
} }
void class11() void class11()