Memory leaks: Refactoring to use Tokenizer::FindClassFunction. Enabled test case, the memory leak is now detected
This commit is contained in:
parent
01c39daa13
commit
02df14ec37
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue