From af1e51f6489a33695499c84695d2c3543bdc93cb Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 14 Jul 2011 20:45:27 -0400 Subject: [PATCH] fix some more false negatives for #2904 (Memory leak not detected when creating a new class instance) --- lib/checkmemoryleak.cpp | 28 +++++++++++++--------------- lib/checkmemoryleak.h | 2 +- test/testmemleak.cpp | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 2528f4fd3..4f985b044 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -82,23 +82,21 @@ static int call_func_white_list_compare(const void *a, const void *b) //--------------------------------------------------------------------------- -bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) const +bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok, unsigned int varid) const { if (tok->isStandardType()) return false; - // return false if the type is a simple struct without member functions - const std::string pattern("struct|class " + tok->str() + " {"); - const Token *tok2 = Token::findmatch(_tokenizer->tokens(), pattern.c_str()); - if (tok2) - { - while (tok2 && tok2->str() != "}" && tok2->str() != "(") - tok2 = tok2->next(); + const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(varid); - // Simple struct => return false - if (tok2 && tok2->str() == "}") - return false; - } + // return false if the type is a simple record type without side effects + // a type that has no side effects (no constructors and no members with constructors) + /** @todo false negative: check base class for side effects */ + /** @todo false negative: check constructors for side effects */ + if (var && var->type() && var->type()->numConstructors == 0 && + (var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) && + var->type()->derivedFrom.empty()) + return false; return true; } @@ -1039,21 +1037,21 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listtokAt(2), "new %type% [(;]")) { - if (isclass(_tokenizer, tok->tokAt(3))) + if (isclass(_tokenizer, tok->tokAt(3), varid)) { alloc = No; } } else if (Token::Match(tok->tokAt(2), "new ( nothrow ) %type%")) { - if (isclass(_tokenizer, tok->tokAt(6))) + if (isclass(_tokenizer, tok->tokAt(6), varid)) { alloc = No; } } else if (Token::Match(tok->tokAt(2), "new ( std :: nothrow ) %type%")) { - if (isclass(_tokenizer, tok->tokAt(8))) + if (isclass(_tokenizer, tok->tokAt(8), varid)) { alloc = No; } diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index f82918ab9..2a036efc7 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -127,7 +127,7 @@ public: * @param typestr type name * @return true if the type name is the name of a class */ - bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const; + bool isclass(const Tokenizer *_tokenizer, const Token *typestr, unsigned int varid) const; void memleakError(const Token *tok, const std::string &varname); void resourceLeakError(const Token *tok, const std::string &varname); diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 20cc153f5..abb9d7ec9 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -2236,6 +2236,21 @@ private: " Fred *f = new Fred();\n" "}\n"); ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: f\n", errout.str()); + + check("class Fred { void foo(){ } };\n" + "void f(void) \n" + "{\n" + " Fred *f = new Fred();\n" + " delete f;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("class Fred { void foo(){ } };\n" + "void f(void) \n" + "{\n" + " Fred *f = new Fred();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: f\n", errout.str()); } void allocfunc1()