From 38741868b5fe5b39378e9d9e18b839ef1677ff19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 26 May 2016 17:42:27 +0200 Subject: [PATCH] Fixed #3989 (false positive: memory leak (inline function)) --- lib/checkleakautovar.cpp | 3 +++ lib/checkmemoryleak.cpp | 7 +++++-- lib/symboldatabase.cpp | 11 ++++++++++- lib/symboldatabase.h | 3 +++ test/testleakautovar.cpp | 15 +++++++++++++++ test/testmemleak.cpp | 15 +++++++++++++++ 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index f167afa5d..28bd714e0 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -140,6 +140,9 @@ void CheckLeakAutoVar::check() const std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t i = 0; i < functions; ++i) { const Scope * scope = symbolDatabase->functionScopes[i]; + if (scope->hasInlineFunction()) + continue; + // Empty variable info VarInfo varInfo; diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 8c36cde81..5878dee10 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -2177,8 +2177,8 @@ void CheckMemoryLeakInFunction::check() const std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t i = 0; i < functions; ++i) { const Scope * scope = symbolDatabase->functionScopes[i]; - - checkScope(scope->classStart->next(), "", 0, scope->functionOf != nullptr, 1); + if (!scope->hasInlineFunction()) + checkScope(scope->classStart->next(), "", 0, scope->functionOf != nullptr, 1); } // Check variables.. @@ -2197,6 +2197,9 @@ void CheckMemoryLeakInFunction::check() if (var->isPointer() && var->type() && !var->typeScope()) continue; + if (var->scope()->hasInlineFunction()) + continue; + unsigned int sz = _tokenizer->sizeOfType(var->typeStartToken()); if (sz < 1) sz = 1; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 3aae6e933..7f209ef1e 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -3493,7 +3493,16 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty return nullptr; } -//--------------------------------------------------------------------------- +bool Scope::hasInlineFunction() const +{ + for (std::list::const_iterator it = nestedList.begin(); it != nestedList.end(); ++it) { + const Scope *s = *it; + // Inline function + if (s->type == Scope::eUnconditional && Token::Match(s->classStart->previous(), ") {")) + return true; + } + return false; +} void Scope::findFunctionInBase(const std::string & name, size_t args, std::vector & matches) const { diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 2688b6801..b2744d2ba 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -898,6 +898,9 @@ public: type == eTry || type == eCatch); } + // Is there lambda/inline function(s) in this scope? + bool hasInlineFunction() const; + /** * @brief find a function * @param tok token of function call diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index b81beebca..bcc7a20a3 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -121,6 +121,8 @@ private: TEST_CASE(nestedAllocation); TEST_CASE(testKeywords); // #6767 + + TEST_CASE(inlineFunction); // #3989 } void check(const char code[], bool cpp = false) { @@ -1223,6 +1225,19 @@ private: "}", false); ASSERT_EQUALS("", errout.str()); } + + void inlineFunction() { + check("int test() {\n" + " char *c;\n" + " int ret() {\n" + " free(c);\n" + " return 0;\n" + " }\n" + " c = malloc(128);\n" + " return ret();\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestLeakAutoVar) diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index ee462a639..887e43ae3 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -250,6 +250,8 @@ private: TEST_CASE(allocfunc13); // Ticket #4494 and #4540 - class function TEST_CASE(allocfunc14); // Use pointer before returning it + TEST_CASE(inlineFunction); // #3989 - inline function + TEST_CASE(throw1); TEST_CASE(throw2); @@ -2679,6 +2681,19 @@ private: ASSERT_EQUALS("", errout.str()); } + void inlineFunction() { // #3989 - inline function + check("int test() {\n" + " char *c;\n" + " int ret() {\n" + " free(c);\n" + " return 0;\n" + " }\n" + " c = malloc(128);\n" + " return ret();\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void throw1() { check("void foo()\n" "{\n"