diff --git a/CheckMemoryLeak.cpp b/CheckMemoryLeak.cpp index 918d2f8a3..16d32e01e 100644 --- a/CheckMemoryLeak.cpp +++ b/CheckMemoryLeak.cpp @@ -25,6 +25,7 @@ #include // free +#include #include #include @@ -39,7 +40,7 @@ #endif //--------------------------------------------------------------------------- - +static TOKEN *getcode(const TOKEN *tok, const char varname[]); static bool isclass( const std::string &typestr ) { @@ -174,7 +175,61 @@ static AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[] ) return No; } -//--------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + +static std::list callstack; + +static const char * call_func( const TOKEN *tok, const char *varnames[] ) +{ + if (GetAllocationType(tok)!=No || GetDeallocationType(tok,varnames)!=No) + return 0; + + const char *funcname = tok->str; + if ( std::find(callstack.begin(), callstack.end(), std::string(funcname)) != callstack.end() ) + return "use"; + callstack.push_back(funcname); + + int par = 1; + int parlevel = 0; + for ( ; tok; tok = tok->next ) + { + if ( Match(tok, "(") ) + ++parlevel; + else if ( Match(tok, ")") ) + { + --parlevel; + if ( parlevel < 1 ) + return NULL; + } + + if ( parlevel == 1 ) + { + if ( Match(tok, ",") ) + ++par; + if ( Match(tok, "[,()] %var1% [,()]", varnames) ) + { + const TOKEN *ftok = GetFunctionTokenByName(funcname); + const char *parname = GetParameterName( ftok, par ); + if ( ! parname ) + return "use"; + // Check if the function deallocates the variable.. + while ( ftok && ! Match(ftok,"{") ) + ftok = ftok->next; + TOKEN *func = getcode( Tokenizer::gettok(ftok,1), parname ); + const char *ret = 0; + if ( findmatch(func, "use") ) + ret = "use"; + if ( findmatch(func, "dealloc") ) + ret = "dealloc"; + deleteTokens(func); + return ret; + } + } + } + return NULL; +} + +//-------------------------------------------------------------------------- static void MismatchError( const TOKEN *Tok1, const char varname[] ) { @@ -374,9 +429,13 @@ static TOKEN *getcode(const TOKEN *tok, const char varname[]) if ( Match(tok,"[)=] %var1% [;)]", varnames) ) addtoken("use"); - // Function parameter.. - if ( Match(tok, "[(,)] %var1% [,)]", varnames) ) - addtoken("use"); + // Investigate function calls.. + if ( Match(tok, "%var% (") ) + { + const char *str = call_func(tok, varnames); + if ( str ) + addtoken( str ); + } // Linux lists.. if ( Match( tok, "[=(,] & %var1% [.[]", varnames ) ) @@ -406,6 +465,8 @@ static void erase(TOKEN *begin, const TOKEN *end) // Simpler but less powerful than "CheckMemoryLeak_CheckScope_All" static void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] ) { + callstack.clear(); + TOKEN *tok = getcode( Tok1, varname ); // If the variable is not allocated at all => no memory leak @@ -415,7 +476,6 @@ static void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] return; } - // Remove "do"... // do { x } while (y); // => diff --git a/CommonCheck.cpp b/CommonCheck.cpp index 55239d5e4..df2bd1687 100644 --- a/CommonCheck.cpp +++ b/CommonCheck.cpp @@ -232,7 +232,21 @@ const TOKEN *GetFunctionTokenByName( const char funcname[] ) } return NULL; } -//--------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + +const char *GetParameterName( const TOKEN *ftok, int par ) +{ + int _par = 1; + for ( ; ftok; ftok = ftok->next) + { + if ( Match(ftok, ",") ) + ++_par; + if ( par==_par && Match(ftok, "%var% [,)]") ) + return ftok->str; + } + return NULL; +} +//-------------------------------------------------------------------------- void CheckGlobalFunctionUsage(const std::vector &filenames) { diff --git a/CommonCheck.h b/CommonCheck.h index 103c2bb98..fceeaa94c 100644 --- a/CommonCheck.h +++ b/CommonCheck.h @@ -48,6 +48,7 @@ bool IsStandardType(const char str[]); void FillFunctionList(const unsigned int file_id); const TOKEN *GetFunctionTokenByName( const char funcname[] ); +const char *GetParameterName( const TOKEN *ftok, int par ); void CheckGlobalFunctionUsage(const std::vector &filenames); bool Match(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0); diff --git a/testmemleak.cpp b/testmemleak.cpp index e5f614efa..daf89017e 100644 --- a/testmemleak.cpp +++ b/testmemleak.cpp @@ -19,6 +19,7 @@ +#include "CommonCheck.h" #include "tokenize.h" #include "CheckMemoryLeak.h" #include "testsuite.h" @@ -49,6 +50,7 @@ private: // Check for memory leaks.. ShowAll = false; + FillFunctionList(0); CheckMemoryLeak(); tokenizer.DeallocateTokens(); @@ -97,6 +99,7 @@ private: TEST_CASE( func1 ); TEST_CASE( func2 ); + TEST_CASE( func3 ); TEST_CASE( class1 ); TEST_CASE( class2 ); @@ -587,6 +590,20 @@ private: } + void func3() + { + check( "static void foo(const char *str)\n" + "{ }\n" + "\n" + "static void f()\n" + "{\n" + " char *p = new char[100];\n" + " foo(p);\n" + "}\n" ); + ASSERT_EQUALS( std::string("[test.cpp:8]: Memory leak: p\n"), errout.str() ); + } + + /* void func3() {