From e49f7bfa0e89af1015efbd01b7d5dbf1308019ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 27 Jan 2010 21:02:13 +0100 Subject: [PATCH] Fixed #1315 (mismatched allocation and deallocaton not detected) --- lib/checkmemoryleak.cpp | 53 +++++++++++++++++++---------------------- lib/checkmemoryleak.h | 8 +++---- test/testmemleak.cpp | 32 ++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index bce233230..f83785164 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -360,9 +360,9 @@ void CheckMemoryLeak::mismatchSizeError(const Token *tok, const std::string &sz) reportErr(tok, Severity::error, "mismatchSize", "The given size " + sz + " is mismatching"); } -void CheckMemoryLeak::mismatchAllocDealloc(const std::list &callstack, const std::string &varname) +void CheckMemoryLeak::mismatchAllocDealloc(const std::list &callstack, const std::string &varname, bool all) { - reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname); + reportErr(callstack, all ? Severity::possibleError : Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname); } CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) const @@ -831,7 +831,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listtokens(), "%varid%", varid)->str()); + mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str(), false); callstack.pop_back(); } @@ -882,7 +882,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listtokens(), "%varid%", varid)->str()); + mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str(), false); callstack.pop_back(); } dealloctype = dealloc; @@ -2237,18 +2237,14 @@ void CheckMemoryLeakInFunction::check() void CheckMemoryLeakInClass::check() { - int indentlevel = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (tok->str() == "{") - ++indentlevel; + tok = tok->link(); - else if (tok->str() == "}") - --indentlevel; - - else if (indentlevel == 0 && Token::Match(tok, "class %var% [{:]")) + else if (Token::Match(tok, "class %var% [{:]")) { - std::vector classname; + std::vector classname; classname.push_back(tok->strAt(1)); parseClass(tok, classname); } @@ -2256,7 +2252,7 @@ void CheckMemoryLeakInClass::check() } -void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector &classname) +void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector &classname) { // Go into class. while (tok1 && tok1->str() != "{") @@ -2311,12 +2307,12 @@ void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector_showAll) return; - const char *varname = tokVarname->strAt(0); + const std::string varname = tokVarname->strAt(0); // Check if member variable has been allocated and deallocated.. CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No; @@ -2327,13 +2323,13 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa // Loop through all tokens. Inspect member functions int indent_ = 0; - const Token *functionToken = Tokenizer::findClassFunction(_tokenizer->tokens(), classname, "~| %var%", indent_); + const Token *functionToken = Tokenizer::findClassFunction(_tokenizer->tokens(), classname.c_str(), "~| %var%", indent_); while (functionToken) { - const bool constructor(Token::Match(functionToken, (classname + std::string(" :: ") + classname + " (").c_str())); + const bool constructor(Token::Match(functionToken, (classname + " :: " + classname + " (").c_str())); const bool destructor(functionToken->tokAt(2)->str() == "~"); - int indent = 0; + unsigned int indent = 0; bool initlist = false; for (const Token *tok = functionToken; tok; tok = tok->next()) { @@ -2341,9 +2337,9 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa ++indent; else if (tok->str() == "}") { - --indent; - if (indent <= 0) + if (indent <= 1) break; + --indent; } else if (indent == 0 && Token::simpleMatch(tok, ") :")) initlist = true; @@ -2351,12 +2347,12 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa { if (indent == 0) { - if (!Token::Match(tok, (":|, " + std::string(varname) + " (").c_str())) + if (!Token::Match(tok, (":|, " + varname + " (").c_str())) continue; } // Allocate.. - if (indent == 0 || Token::Match(tok, (std::string(varname) + " =").c_str())) + if (indent == 0 || Token::Match(tok, (varname + " =").c_str())) { AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3), 0); if (alloc != CheckMemoryLeak::No) @@ -2371,7 +2367,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa if (alloc != CheckMemoryLeak::Many && Dealloc != CheckMemoryLeak::No && Dealloc != CheckMemoryLeak::Many && Dealloc != alloc) { callstack.push_back(tok); - mismatchAllocDealloc(callstack, (std::string(classname) + "::" + varname).c_str()); + mismatchAllocDealloc(callstack, classname + "::" + varname, true); callstack.pop_back(); } @@ -2384,12 +2380,12 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa // Deallocate.. const char *varnames[3] = { "var", 0, 0 }; - varnames[0] = varname; + varnames[0] = varname.c_str(); AllocType dealloc = getDeallocationType(tok, varnames); if (dealloc == No) { varnames[0] = "this"; - varnames[1] = varname; + varnames[1] = varname.c_str(); dealloc = getDeallocationType(tok, varnames); } if (dealloc != CheckMemoryLeak::No) @@ -2397,6 +2393,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa if (destructor) deallocInDestructor = true; + // several types of allocation/deallocation? if (Dealloc != CheckMemoryLeak::No && Dealloc != dealloc) dealloc = CheckMemoryLeak::Many; @@ -2404,7 +2401,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa if (dealloc != CheckMemoryLeak::Many && Alloc != CheckMemoryLeak::No && Alloc != Many && Alloc != dealloc) { callstack.push_back(tok); - mismatchAllocDealloc(callstack, (std::string(classname) + "::" + varname).c_str()); + mismatchAllocDealloc(callstack, classname + "::" + varname, true); callstack.pop_back(); } @@ -2424,16 +2421,16 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa } } - functionToken = Tokenizer::findClassFunction(functionToken->next(), classname, "~| %var%", indent_); + functionToken = Tokenizer::findClassFunction(functionToken->next(), classname.c_str(), "~| %var%", indent_); } if (allocInConstructor && !deallocInDestructor) { - memoryLeak(tokVarname, (std::string(classname) + "::" + varname).c_str(), Alloc, true); + memoryLeak(tokVarname, (classname + "::" + varname).c_str(), Alloc, true); } else if (Alloc != CheckMemoryLeak::No && Dealloc == CheckMemoryLeak::No) { - memoryLeak(tokVarname, (std::string(classname) + "::" + varname).c_str(), Alloc, true); + memoryLeak(tokVarname, (classname + "::" + varname).c_str(), Alloc, true); } } diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index fd21ee1f3..7665075b7 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -123,7 +123,7 @@ public: void deallocDeallocError(const Token *tok, const std::string &varname); void deallocuseError(const Token *tok, const std::string &varname); void mismatchSizeError(const Token *tok, const std::string &sz); - void mismatchAllocDealloc(const std::list &callstack, const std::string &varname); + void mismatchAllocDealloc(const std::list &callstack, const std::string &varname, bool all); /** What type of allocated memory does the given function return? */ AllocType functionReturnType(const Token *tok) const; @@ -272,7 +272,7 @@ private: deallocuseError(0, "varname"); mismatchSizeError(0, "sz"); std::list callstack; - mismatchAllocDealloc(callstack, "varname"); + mismatchAllocDealloc(callstack, "varname", false); } std::string name() const @@ -314,8 +314,8 @@ public: void check(); private: - void parseClass(const Token *tok1, std::vector &classname); - void variable(const char classname[], const Token *tokVarname); + void parseClass(const Token *tok1, std::vector &classname); + void variable(const std::string &classname, const Token *tokVarname); void getErrorMessages() { } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 85f4b22d6..5d0f5d4ff 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -2727,6 +2727,8 @@ private: TEST_CASE(use); TEST_CASE(free_member_in_sub_func); + + TEST_CASE(mismatch1); } @@ -2778,7 +2780,7 @@ private: " free(str1);\n" "}\n", true); - ASSERT_EQUALS("[test.cpp:17]: (error) Mismatching allocation and deallocation: Fred::str1\n", errout.str()); + ASSERT_EQUALS("[test.cpp:17]: (possible error) Mismatching allocation and deallocation: Fred::str1\n", errout.str()); } void class3() @@ -3080,6 +3082,34 @@ private: "}\n", true); ASSERT_EQUALS("", errout.str()); } + + void mismatch1() + { + check("class A\n" + "{\n" + "public:\n" + " A(int i);\n" + " ~A();\n" + "private:\n" + " char* pkt_buffer;\n" + "};\n" + "\n" + "A::A(int i)\n" + "{\n" + " pkt_buffer = new char[8192];\n" + " if (i != 1) {\n" + " delete pkt_buffer;\n" + " pkt_buffer = 0;\n" + " }\n" + "}\n" + "\n" + "A::~A() {\n" + " delete [] pkt_buffer;\n" + "}\n", true); + ASSERT_EQUALS("[test.cpp:14]: (possible error) Mismatching allocation and deallocation: A::pkt_buffer\n", errout.str()); + } + + }; static TestMemleakInClass testMemleakInClass;