From 3c289e52c5459a89128407c666e062380318f86c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 7 Feb 2009 10:54:39 +0000 Subject: [PATCH] memory allocation: check for mismatching size --- src/checkmemoryleak.cpp | 29 ++++++++++++++++++++--------- src/checkmemoryleak.h | 6 +++--- src/errormessage.h | 9 +++++++++ src/tokenize.cpp | 16 +++++++++++----- test/testmemleak.cpp | 13 +++++++++++++ tools/errmsg.cpp | 1 + 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/checkmemoryleak.cpp b/src/checkmemoryleak.cpp index 9d984c595..2a189a082 100644 --- a/src/checkmemoryleak.cpp +++ b/src/checkmemoryleak.cpp @@ -193,7 +193,7 @@ CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetDeallocationType(const } //-------------------------------------------------------------------------- -const char * CheckMemoryLeakClass::call_func(const Token *tok, std::list callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all) +const char * CheckMemoryLeakClass::call_func(const Token *tok, std::list callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz) { // Keywords that are not function calls.. if (Token::Match(tok, "if|for|while")) @@ -266,7 +266,7 @@ const char * CheckMemoryLeakClass::call_func(const Token *tok, std::liststr() != "{")) ftok = ftok->next(); - Token *func = getcode(ftok->tokAt(1), callstack, parname, alloctype, dealloctype, false, all); + Token *func = getcode(ftok->tokAt(1), callstack, parname, alloctype, dealloctype, false, all, sz); simplifycode(func); const Token *func_ = func; while (func_ && func_->str() == ";") @@ -327,7 +327,7 @@ bool CheckMemoryLeakClass::notvar(const Token *tok, const char *varnames[], bool Token::simpleMatch(tok, std::string(varname + " == 0" + end).c_str())); } -Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all) +Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz) { const char *varnames[2]; varnames[0] = varname; @@ -389,6 +389,13 @@ Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list AllocType alloc = GetAllocationType(tok->tokAt(2)); bool realloc = false; + if (sz > 1 && + Token::Match(tok->tokAt(2), "malloc ( %num% )") && + (atoi(tok->strAt(4)) % sz) != 0) + { + ErrorMessage::mismatchSize(_errorLogger, _tokenizer, tok->tokAt(4), tok->strAt(4)); + } + if (alloc == No) { alloc = GetReallocationType(tok->tokAt(2)); @@ -642,7 +649,7 @@ Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list else { - const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype, all); + const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype, all, sz); if (str) addtoken(str); } @@ -1150,7 +1157,7 @@ void CheckMemoryLeakClass::simplifycode(Token *tok) // Check for memory leaks for a function variable. -void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember) +void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz) { std::list callstack; @@ -1161,7 +1168,7 @@ void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const c const Token *result; - Token *tok = getcode(Tok1, callstack, varname, alloctype, dealloctype, classmember, all); + Token *tok = getcode(Tok1, callstack, varname, alloctype, dealloctype, classmember, all, sz); //tok->printOut( "getcode result" ); // Simplify the code and check if freed memory is used.. @@ -1318,11 +1325,15 @@ void CheckMemoryLeakClass::CheckMemoryLeak_InFunction() // Declare a local variable => Check if (indentlevel > 0 && infunc) { + unsigned int sz = _tokenizer->SizeOfType(tok->strAt(1)); + if (sz < 1) + sz = 1; + if (Token::Match(tok, "[{};] %type% * %var% [;=]")) - CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(3), classmember); + CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(3), classmember, sz); else if (Token::Match(tok, "[{};] %type% %type% * %var% [;=]")) - CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(4), classmember); + CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(4), classmember, sz); } } } @@ -1574,7 +1585,7 @@ Token * CheckMemoryLeakClass::functionParameterCode(const Token *ftok, int param AllocType alloc = No, dealloc = No; bool all = false; std::list callstack; - Token *code = getcode(ftok, callstack, parname, alloc, dealloc, false, all); + Token *code = getcode(ftok, callstack, parname, alloc, dealloc, false, all, 1); simplifycode(code); return code; } diff --git a/src/checkmemoryleak.h b/src/checkmemoryleak.h index 93b254b75..3e22b630c 100644 --- a/src/checkmemoryleak.h +++ b/src/checkmemoryleak.h @@ -62,7 +62,7 @@ private: void CheckMemoryLeak_ClassMembers_ParseClass(const Token *tok1, std::vector &classname); void CheckMemoryLeak_ClassMembers(); void CheckMemoryLeak_InFunction(); - void CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember); + void CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz); /** * Simplify code e.g. by replacing empty "{ }" with ";" @@ -89,7 +89,7 @@ private: * @return Newly allocated token array. Caller needs to release reserved * memory by calling Tokenizer::deleteTokens(returnValue); */ - Token *getcode(const Token *tok, std::list callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all); + Token *getcode(const Token *tok, std::list callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz); /** * Check if there is a "!var" match inside a condition @@ -103,7 +103,7 @@ private: bool MatchFunctionsThatReturnArg(const Token *tok, const std::string &varname); void MemoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all); void MismatchError(const Token *Tok1, const std::list &callstack, const char varname[]); - const char * call_func(const Token *tok, std::list callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all); + const char * call_func(const Token *tok, std::list callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz); AllocType GetDeallocationType(const Token *tok, const char *varnames[]); AllocType GetAllocationType(const Token *tok2); AllocType GetReallocationType(const Token *tok2); diff --git a/src/errormessage.h b/src/errormessage.h index cae17a454..9d4720590 100644 --- a/src/errormessage.h +++ b/src/errormessage.h @@ -188,6 +188,15 @@ public: return true; } + static void mismatchSize(ErrorLogger *logger, const Tokenizer *tokenizer, const Token *Location, const std::string &sz) + { + _writemsg(logger, tokenizer, Location, "all", "The given size " + sz + " is mismatching", "mismatchSize"); + } + static bool mismatchSize(const Settings &s) + { + return s._showAll; + } + static void cstyleCast(ErrorLogger *logger, const Tokenizer *tokenizer, const Token *Location) { _writemsg(logger, tokenizer, Location, "style", "C-style pointer casting", "cstyleCast"); diff --git a/src/tokenize.cpp b/src/tokenize.cpp index 98355fa95..d18dcea00 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -1249,13 +1249,19 @@ bool Tokenizer::simplifyConditions() } // Change numeric constant in condition to "true" or "false" - const Token *tok2 = tok->tokAt(2); - if ((tok->str() == "(" || tok->str() == "&&" || tok->str() == "||") && - Token::Match(tok->next(), "%num%") && - tok2 && + if (Token::Match(tok, "if|while ( %num%") && + (tok->tokAt(3)->str() == ")" || tok->tokAt(3)->str() == "||" || tok->tokAt(3)->str() == "&&")) + { + tok->next()->next()->str((tok->tokAt(2)->str() != "0") ? "true" : "false"); + ret = true; + } + Token *tok2 = tok->tokAt(2); + if (tok2 && + (tok->str() == "&&" || tok->str() == "||") && + Token::Match(tok->next(), "%num%") && (tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||")) { - tok->next()->str((tok->next()->str() != "0") ? "true" : "false"); + tok->next()->str(); ret = true; } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index bf1c6f46f..492758a2b 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -184,6 +184,8 @@ private: TEST_CASE(strcat_result_assignment); TEST_CASE(all1); // Extra checking when --all is given + + TEST_CASE(malloc_constant_1); // Check that the malloc constant matches the type } @@ -1807,6 +1809,17 @@ private: ASSERT_EQUALS(std::string("[test.cpp:4]: (all) Memory leak: f\n"), errout.str()); } + + + void malloc_constant_1() + { + check("void foo()\n" + "{\n" + " int *p = malloc(3);\n" + " free(p);\n" + "}\n", false); + ASSERT_EQUALS(std::string("[test.cpp:3]: (all) The given size 3 is mismatching\n"), errout.str()); + } }; REGISTER_TEST(TestMemleak) diff --git a/tools/errmsg.cpp b/tools/errmsg.cpp index 1c086c9ce..dbc96598b 100644 --- a/tools/errmsg.cpp +++ b/tools/errmsg.cpp @@ -81,6 +81,7 @@ int main() err.push_back(Message("resourceLeak", Message::error, "Resource leak: %1", "varname")); err.push_back(Message("deallocDealloc", Message::error, "Deallocating a deallocated pointer: %1", "varname")); err.push_back(Message("deallocuse", Message::error, "Using '%1' after it is deallocated / released", "varname")); + err.push_back(Message("mismatchSize", Message::all, "The given size %1 is mismatching", "sz")); // checkother.cpp.. err.push_back(Message("cstyleCast", Message::style, "C-style pointer casting"));