diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 263ebb7ff..cd66629f1 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -424,6 +424,45 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) return No; } + +void CheckMemoryLeakInFunction::parse_noreturn() +{ + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (tok->str() == "{") + tok = tok->link(); + if (tok->str() == "(") + { + const std::string function_name((tok->previous() && tok->previous()->isName()) ? tok->strAt(-1) : ""); + + tok = tok->link(); + + if (!function_name.empty() && Token::simpleMatch(tok, ") {")) + { + // parse this function to check if it contains an "exit" call.. + unsigned int indentlevel = 0; + for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + ++indentlevel; + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + if (Token::Match(tok2, "[;{}] exit (")) + { + noreturn.insert(function_name); + break; + } + } + } + } + } +} + + bool CheckMemoryLeakInFunction::matchFunctionsThatReturnArg(const Token *tok, unsigned int varid) const { return Token::Match(tok, "; %varid% = strcat|memcpy|memmove|strcpy ( %varid% ,", varid); @@ -473,6 +512,9 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::liststr()) != noreturn.end()) + return "exit"; + if (varid > 0 && (getAllocationType(tok, varid) != No || getReallocationType(tok, varid) != No || getDeallocationType(tok, varid) != No)) return 0; @@ -1891,6 +1933,9 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string void CheckMemoryLeakInFunction::check() { + // Parse the tokens and fill the "noreturn" + parse_noreturn(); + bool classmember = false; bool beforeParameters = false; bool infunc = false; diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index b84789bdc..8f64f3c3e 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -165,6 +165,7 @@ public: private: #endif + bool matchFunctionsThatReturnArg(const Token *tok, unsigned int varid) const; /** @@ -271,6 +272,9 @@ private: { return "Is there any allocated memory when a function goes out of scope"; } + + void parse_noreturn(); + std::set noreturn; }; diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 5c4c9e475..4eb1ddb51 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -247,6 +247,7 @@ private: TEST_CASE(exit2); TEST_CASE(exit4); TEST_CASE(exit5); + TEST_CASE(noreturn); TEST_CASE(stdstring); TEST_CASE(strndup_function); @@ -2071,6 +2072,19 @@ private: ASSERT_EQUALS("", errout.str()); } + void noreturn() + { + check("void fatal_error()\n" + "{ exit(1); }\n" + "\n" + "void f()\n" + "{\n" + " char *p = malloc(100);\n" + " fatal_error();\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void stdstring()