From 03e44d4aa07b2ed9133c20e0ebfc17aaad6837af Mon Sep 17 00:00:00 2001 From: PKEuS Date: Fri, 30 Jan 2015 20:55:53 +0100 Subject: [PATCH] CheckMemoryLeakInFunction: Don't treat delete as delete operator for C code Fixed GCC message in checkbufferoverrun.cpp --- lib/checkbufferoverrun.cpp | 2 +- lib/checkmemoryleak.cpp | 64 ++++++++++++++++++-------------------- lib/checkmemoryleak.h | 6 ++-- test/testmemleak.cpp | 64 ++++++++++++++++++++++++-------------- 4 files changed, 75 insertions(+), 61 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 5a653f142..823c8a4a0 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -654,7 +654,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector 0) { // Writing data into array.. - if (total_size > 0 && (declarationId > 0 && Token::Match(tok, "strcpy|strcat ( %varid% , %str% )", declarationId)) || + if ((declarationId > 0 && Token::Match(tok, "strcpy|strcat ( %varid% , %str% )", declarationId)) || (declarationId == 0 && Token::Match(tok, ("strcpy|strcat ( " + varnames + " , %str% )").c_str()))) { const std::size_t len = Token::getStrLength(tok->tokAt(varcount + 4)); if (len >= (unsigned int)total_size) { diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 1f1cbb455..257899468 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -64,7 +64,7 @@ static unsigned int countParameters(const Token *tok) static const char * const call_func_white_list[] = { "_open", "_wopen", "access", "adjtime", "asctime", "asctime_r", "asprintf", "assert" , "atof", "atoi", "atol", "chdir", "chmod", "chown" - , "clearerr", "creat", "ctime", "ctime_r", "delete", "execl", "execle" + , "clearerr", "creat", "ctime", "ctime_r", "execl", "execle" , "execlp", "execv", "execve", "fchmod", "fclose", "fcntl" , "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets" , "flock", "fmemopen", "fnmatch", "fopen", "fopencookie", "for", "fprintf", "fputc", "fputs", "fread", "free" @@ -239,17 +239,19 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, unsigned int varid) const { - if (Token::Match(tok, "delete %varid% ;", varid)) - return New; + if (tokenizer->isCPP()) { + if (Token::Match(tok, "delete %varid% ;", varid)) + return New; - if (Token::Match(tok, "delete [ ] %varid% ;", varid)) - return NewArray; + if (Token::Match(tok, "delete [ ] %varid% ;", varid)) + return NewArray; - if (Token::Match(tok, "delete ( %varid% ) ;", varid)) - return New; + if (Token::Match(tok, "delete ( %varid% ) ;", varid)) + return New; - if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid)) - return NewArray; + if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid)) + return NewArray; + } if (tok && tok->str() == "::") tok = tok->next(); @@ -283,17 +285,19 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const std::string &varname) const { - if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str())) - return New; + if (tokenizer->isCPP()) { + if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str())) + return New; - if (Token::Match(tok, std::string("delete [ ] " + varname + " [,;]").c_str())) - return NewArray; + if (Token::Match(tok, std::string("delete [ ] " + varname + " [,;]").c_str())) + return NewArray; - if (Token::Match(tok, std::string("delete ( " + varname + " ) [,;]").c_str())) - return New; + if (Token::Match(tok, std::string("delete ( " + varname + " ) [,;]").c_str())) + return New; - if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str())) - return NewArray; + if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str())) + return NewArray; + } if (Token::simpleMatch(tok, std::string("free ( " + varname + " ) ;").c_str()) || Token::simpleMatch(tok, std::string("kfree ( " + varname + " ) ;").c_str()) || @@ -523,25 +527,17 @@ bool CheckMemoryLeakInFunction::notvar(const Token *tok, unsigned int varid, boo -bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname) +bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname, const Settings *settings, bool cpp) { return (std::binary_search(call_func_white_list, call_func_white_list+sizeof(call_func_white_list) / sizeof(call_func_white_list[0]), - funcname)); -} - - -bool CheckMemoryLeakInFunction::test_white_list_with_lib(const std::string &funcname, const Settings *settings) -{ - return (std::binary_search(call_func_white_list, - call_func_white_list+sizeof(call_func_white_list) / sizeof(call_func_white_list[0]), - funcname) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end())); + funcname) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end()) || (cpp && funcname == "delete")); } const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &allocpar, unsigned int sz) { - if (test_white_list_with_lib(tok->str(), _settings)) { + if (test_white_list(tok->str(), _settings, tokenizer->isCPP())) { if (tok->str() == "asprintf" || tok->str() == "delete" || tok->str() == "fclose" || @@ -1024,7 +1020,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::liststr(), _settings)) { + } else if (Token::Match(tok2, "%var% (") && !test_white_list(tok2->str(), _settings, tokenizer->isCPP())) { bool use = false; for (const Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->nextArgument()) { if (Token::Match(tok3->previous(), "(|, &| %varid% ,|)", varid)) { @@ -1200,7 +1196,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listprevious(), "&|(") && tok2->strAt(1) == "[") { } else if (f.empty() || - !test_white_list_with_lib(f.top()->str(), _settings) || + !test_white_list(f.top()->str(), _settings, tokenizer->isCPP()) || getDeallocationType(f.top(),varid)) { use = true; } @@ -1286,7 +1282,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listlibrary.isnoreturn(tok)) addtoken(&rettail, tok, "exit"); - else if (!test_white_list_with_lib(tok->str(), _settings)) { + else if (!test_white_list(tok->str(), _settings, tokenizer->isCPP())) { const Token* const end2 = tok->linkAt(1); for (const Token *tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) { if (tok2->varId() == varid) { @@ -2402,7 +2398,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam // Function call .. possible deallocation else if (Token::Match(tok->previous(), "[{};] %var% (")) { - if (!CheckMemoryLeakInFunction::test_white_list_with_lib(tok->str(), _settings)) { + if (!CheckMemoryLeakInFunction::test_white_list(tok->str(), _settings, tokenizer->isCPP())) { return; } } @@ -2717,12 +2713,12 @@ void CheckMemoryLeakNoVar::check() // Is it a function call.. if (!Token::Match(tok3->tokAt(-2), "= %var% (")) { const std::string& functionName = tok3->strAt(-1); - if (functionName == "delete" || + if ((tokenizer->isCPP() && functionName == "delete") || functionName == "free" || functionName == "fclose" || functionName == "realloc") break; - if (CheckMemoryLeakInFunction::test_white_list_with_lib(functionName, _settings)) { + if (CheckMemoryLeakInFunction::test_white_list(functionName, _settings, tokenizer->isCPP())) { functionCallLeak(tok2, tok2->strAt(1), functionName); break; } diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index 2d7711dc3..d75d1c14a 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -47,10 +47,11 @@ class Variable; /** @brief Base class for memory leaks checking */ class CPPCHECKLIB CheckMemoryLeak { -private: +protected: /** For access to the tokens */ const Tokenizer * const tokenizer; +private: /** ErrorLogger used to report errors */ ErrorLogger * const errorLogger; @@ -202,8 +203,7 @@ public: } /** @brief Unit testing : testing the white list */ - static bool test_white_list(const std::string &funcname); - static bool test_white_list_with_lib(const std::string &funcname, const Settings *settings); + static bool test_white_list(const std::string &funcname, const Settings *settings, bool cpp); /** @brief Perform checking */ void check(); diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index ac9c45bc1..cca945087 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -128,7 +128,7 @@ private: Settings settings1; Settings settings2; - void check(const char code[], const Settings *settings = nullptr) { + void check(const char code[], const Settings *settings = nullptr, bool c = false) { // Clear the error buffer.. errout.str(""); @@ -138,7 +138,7 @@ private: // Tokenize.. Tokenizer tokenizer(settings, this); std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); + tokenizer.tokenize(istr, c?"test.c":"test.cpp"); tokenizer.simplifyTokenList2(); // Check for memory leaks.. @@ -365,6 +365,8 @@ private: TEST_CASE(ptrptr); + TEST_CASE(c_code); + // test that the cfg files are configured correctly TEST_CASE(posixcfg); TEST_CASE(posixcfg_mmap); @@ -594,33 +596,39 @@ private: ASSERT_EQUALS(";;catch{}", getcode("char *s; catch(err) { }", "s")); } + bool test_white_list(const std::string& str, bool cpp = true) const { + return CheckMemoryLeakInFunction::test_white_list(str, &settings1, cpp); + } void call_func() const { // whitelist.. - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("qsort")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("scanf")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("sscanf")); + ASSERT_EQUALS(true, test_white_list("qsort")); + ASSERT_EQUALS(true, test_white_list("scanf")); + ASSERT_EQUALS(true, test_white_list("sscanf")); // #1293 - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("time")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("asctime")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("asctime_r")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("ctime")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("ctime_r")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gmtime")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gmtime_r")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("localtime")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("localtime_r")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("memcmp")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gets")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vprintf")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vfprintf")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vsprintf")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("snprintf")); - ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vsnprintf")); + ASSERT_EQUALS(true, test_white_list("time")); + ASSERT_EQUALS(true, test_white_list("asctime")); + ASSERT_EQUALS(true, test_white_list("asctime_r")); + ASSERT_EQUALS(true, test_white_list("ctime")); + ASSERT_EQUALS(true, test_white_list("ctime_r")); + ASSERT_EQUALS(true, test_white_list("gmtime")); + ASSERT_EQUALS(true, test_white_list("gmtime_r")); + ASSERT_EQUALS(true, test_white_list("localtime")); + ASSERT_EQUALS(true, test_white_list("localtime_r")); + ASSERT_EQUALS(true, test_white_list("memcmp")); + ASSERT_EQUALS(true, test_white_list("gets")); + ASSERT_EQUALS(true, test_white_list("vprintf")); + ASSERT_EQUALS(true, test_white_list("vfprintf")); + ASSERT_EQUALS(true, test_white_list("vsprintf")); + ASSERT_EQUALS(true, test_white_list("snprintf")); + ASSERT_EQUALS(true, test_white_list("vsnprintf")); + + ASSERT_EQUALS(true, test_white_list("delete", true)); + ASSERT_EQUALS(false, test_white_list("delete", false)); static const char * const call_func_white_list[] = { - "access", "asprintf", "atof", "atoi", "atol", "chdir", "chmod", "clearerr", "chown", "delete" + "access", "asprintf", "atof", "atoi", "atol", "chdir", "chmod", "clearerr", "chown" , "fchmod", "fcntl", "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets" , "flock", "for", "fprintf", "fputc", "fputs", "fread", "free", "freopen", "fscanf", "fseek" , "fseeko", "fsetpos", "fstat", "fsync", "ftell", "ftello", "ftruncate" @@ -644,7 +652,7 @@ private: }; for (unsigned int i = 0; i < (sizeof(call_func_white_list) / sizeof(char *)); ++i) { - bool ret = CheckMemoryLeakInFunction::test_white_list(call_func_white_list[i]); + bool ret = test_white_list(call_func_white_list[i]); ASSERT_EQUALS("", ret ? "" : call_func_white_list[i]); } } @@ -4262,6 +4270,16 @@ private: ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: p\n", errout.str()); } + void c_code() { + check("int main(void) {\n" + " struct llist *ll = malloc(sizeof(struct llist));\n" + " free(ll);\n" + " ll = NULL;\n" + " delete(ll, ll->top);\n" + "}", nullptr, true); + ASSERT_EQUALS("", errout.str()); + } + void gnucfg() { Settings settings; settings.standards.posix = true;