From 02df14ec37bc7e118673c478c768adfece41b4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 14 Mar 2009 18:21:37 +0100 Subject: [PATCH] Memory leaks: Refactoring to use Tokenizer::FindClassFunction. Enabled test case, the memory leak is now detected --- src/checkmemoryleak.cpp | 140 ++++++++++++++++------------------------ src/checkmemoryleak.h | 2 +- test/testmemleak.cpp | 4 +- 3 files changed, 59 insertions(+), 87 deletions(-) diff --git a/src/checkmemoryleak.cpp b/src/checkmemoryleak.cpp index 0d8db59ba..ecfd8688e 100644 --- a/src/checkmemoryleak.cpp +++ b/src/checkmemoryleak.cpp @@ -1447,122 +1447,94 @@ void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_ParseClass(const Token * if (tok->isName() || Token::Match(tok, "[;}]")) { 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 &classname, const Token *tokVarname) +void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_Variable(const char classname[], const Token *tokVarname) { 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.. AllocType Alloc = No; AllocType Dealloc = No; // Loop through all tokens. Inspect member functions - bool memberfunction = false; - int indentlevel = 0; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + int indent_ = 0; + const Token *functionToken = Tokenizer::FindClassFunction(_tokenizer->tokens(), classname, "~| %var%", indent_); + while (functionToken) { - if (tok->str() == "{") - ++indentlevel; - - else if (tok->str() == "}") - --indentlevel; - - // Set the 'memberfunction' variable.. - if (indentlevel == 0) + int indent = 0; + for (const Token *tok = functionToken; tok; tok = tok->next()) { - if (Token::Match(tok, "[;}]")) - memberfunction = false; - else if (Token::Match(tok, fpattern.str().c_str()) || Token::Match(tok, destructor.str().c_str())) - memberfunction = true; - } - - // Parse member function.. - if (indentlevel > 0 && memberfunction) - { - // Allocate.. - if (Token::Match(tok, varname_eq.str().c_str())) + if (tok->str() == "{") + ++indent; + else if (tok->str() == "}") { - AllocType alloc = GetAllocationType(tok->tokAt(2)); - if (alloc != No) + --indent; + if (indent <= 0) + break; + } + else if (indent > 0) + { + // Allocate.. + if (Token::Match(tok, (std::string(varname) + " =").c_str())) { - if (Alloc != No && Alloc != alloc) - alloc = Many; + AllocType alloc = GetAllocationType(tok->tokAt(2)); + if (alloc != No) + { + if (Alloc != No && Alloc != alloc) + alloc = Many; + + std::list 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 callstack; - if (alloc != Many && Dealloc != No && Dealloc != Many && Dealloc != alloc) + if (dealloc != Many && Alloc != No && Alloc != Many && Alloc != dealloc) { callstack.push_back(tok); - _errorLogger->mismatchAllocDealloc(_tokenizer, callstack, FullVariableName.str()); + _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 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; } - Dealloc = dealloc; } - } + + functionToken = Tokenizer::FindClassFunction(functionToken->next(), classname, "~| %var%", indent_); } if (Alloc != No && Dealloc == No) { - MemoryLeak(tokVarname, FullVariableName.str().c_str(), Alloc, true); + MemoryLeak(tokVarname, (std::string(classname) + "::" + varname).c_str(), Alloc, true); } } diff --git a/src/checkmemoryleak.h b/src/checkmemoryleak.h index f58f08e23..4df740dda 100644 --- a/src/checkmemoryleak.h +++ b/src/checkmemoryleak.h @@ -58,7 +58,7 @@ private: } }; - void CheckMemoryLeak_ClassMembers_Variable(const std::vector &classname, const Token *tokVarname); + void CheckMemoryLeak_ClassMembers_Variable(const char classname[], const Token *tokVarname); void CheckMemoryLeak_ClassMembers_ParseClass(const Token *tok1, std::vector &classname); void CheckMemoryLeak_ClassMembers(); void CheckMemoryLeak_InFunction(); diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index a5e5d7697..07bbc7b4f 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -152,7 +152,7 @@ private: TEST_CASE(class7); TEST_CASE(class8); TEST_CASE(class9); - // TODO TEST_CASE(class10); + TEST_CASE(class10); // TODO TEST_CASE(class11); TEST_CASE(throw1); @@ -1525,7 +1525,7 @@ private: " int * p;\n" " A() { p = new int; }\n" "};\n", true); - ASSERT_EQUALS("memory leak", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (all) Memory leak: A::p\n", errout.str()); } void class11()