2009-01-15 21:34:39 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2010-04-13 21:23:17 +02:00
* Copyright ( C ) 2007 - 2010 Daniel Marjamäki and Cppcheck team .
2009-01-15 21:34:39 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-15 21:34:39 +01:00
*/
# include "checkmemoryleak.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2009-03-20 18:16:21 +01:00
# include "tokenize.h"
2009-12-14 20:30:31 +01:00
# include "executionpath.h"
2009-03-20 18:16:21 +01:00
2009-01-15 21:34:39 +01:00
# include <algorithm>
2009-01-23 21:55:06 +01:00
# include <cstring>
2009-08-22 20:23:03 +02:00
# include <cstdlib>
2009-01-15 21:34:39 +01:00
# include <iostream>
# include <sstream>
2009-07-22 08:30:51 +02:00
# include <set>
2009-01-15 21:34:39 +01:00
//---------------------------------------------------------------------------
2009-03-20 18:16:21 +01:00
// Register this check class (by creating a static instance of it)
namespace
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
CheckMemoryLeakInFunction instance1 ;
CheckMemoryLeakInClass instance2 ;
2009-07-19 16:51:31 +02:00
CheckMemoryLeakStructMember instance3 ;
2009-01-15 21:34:39 +01:00
}
2010-01-20 22:03:06 +01:00
2009-08-22 20:23:03 +02:00
// This list needs to be alphabetically sorted so we can run bsearch on it
static const char * const call_func_white_list [ ] =
{
2010-01-20 22:03:06 +01:00
" asctime " , " asctime_r " , " asprintf " , " atof " , " atoi " , " atol " , " clearerr "
, " ctime " , " ctime_r " , " delete " , " fchmod " , " fcntl "
2009-08-22 20:23:03 +02:00
, " fdatasync " , " feof " , " ferror " , " fflush " , " fgetc " , " fgetpos " , " fgets "
2010-01-12 21:56:22 +01:00
, " flock " , " for " , " fprintf " , " fputc " , " fputs " , " fread " , " free " , " fscanf " , " fseek "
2009-08-22 20:23:03 +02:00
, " fseeko " , " fsetpos " , " fstat " , " fsync " , " ftell " , " ftello " , " ftruncate "
2010-01-20 22:03:06 +01:00
, " fwrite " , " getc " , " gets " , " gmtime " , " gmtime_r " , " if " , " ioctl "
, " localtime " , " localtime_r "
, " lockf " , " lseek " , " memchr " , " memcmp " , " memcpy " , " memmove " , " memset "
, " posix_fadvise " , " posix_fallocate " , " pread "
2010-01-18 21:34:11 +01:00
, " printf " , " puts " , " pwrite " , " qsort " , " read " , " readahead " , " readdir " , " readdir_r " , " readv "
2010-01-18 21:58:27 +01:00
, " realloc " , " return " , " rewind " , " rewinddir " , " scandir " , " scanf " , " seekdir "
, " setbuf " , " setbuffer " , " setlinebuf " , " setvbuf " , " snprintf " , " sprintf " , " sscanf " , " strcasecmp "
2010-01-12 22:10:59 +01:00
, " strcat " , " strchr " , " strcmp " , " strcpy " , " stricmp " , " strlen " , " strncat " , " strncmp "
2009-08-22 20:23:03 +02:00
, " strncpy " , " strrchr " , " strstr " , " strtod " , " strtol " , " strtoul " , " switch "
2010-01-20 22:03:06 +01:00
, " sync_file_range " , " telldir " , " time " , " typeid " , " vfprintf " , " vprintf "
, " vsnprintf " , " vsprintf " , " while " , " write " , " writev "
2009-08-22 20:23:03 +02:00
} ;
static int call_func_white_list_compare ( const void * a , const void * b )
{
return strcmp ( ( const char * ) a , * ( const char * * ) b ) ;
}
2009-03-20 18:16:21 +01:00
//---------------------------------------------------------------------------
2009-01-15 21:34:39 +01:00
2009-06-08 20:20:43 +02:00
bool CheckMemoryLeak : : isclass ( const Tokenizer * _tokenizer , const Token * tok ) const
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > isStandardType ( ) )
2009-01-15 21:34:39 +01:00
return false ;
std : : ostringstream pattern ;
pattern < < " struct " < < tok - > str ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . str ( ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return false ;
return true ;
}
//---------------------------------------------------------------------------
2009-08-25 21:25:27 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getAllocationType ( const Token * tok2 , unsigned int varid ) const
2009-01-15 21:34:39 +01:00
{
// What we may have...
// * var = (char *)malloc(10);
// * var = new char[10];
// * var = strdup("hello");
2009-05-19 22:29:10 +02:00
// * var = strndup("hello", 3);
2010-04-02 07:30:58 +02:00
if ( tok2 & & tok2 - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
{
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 ? tok2 - > next ( ) : NULL ;
}
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-01-15 21:34:39 +01:00
return No ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 - > isName ( ) )
2009-01-15 21:34:39 +01:00
return No ;
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
2009-05-21 12:26:44 +02:00
static const char * const mallocfunc [ ] = { " malloc " ,
" calloc " ,
" strdup " ,
" strndup " ,
" kmalloc " ,
" kzalloc " ,
" kcalloc " ,
0
} ;
2010-04-02 07:30:58 +02:00
for ( unsigned int i = 0 ; mallocfunc [ i ] ; i + + )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = mallocfunc [ i ] )
2009-01-15 21:34:39 +01:00
return Malloc ;
}
2009-08-10 22:04:28 +02:00
// Using realloc..
2010-04-02 07:30:58 +02:00
if ( varid & & Token : : Match ( tok2 , " realloc ( %any% , " ) & & tok2 - > tokAt ( 2 ) - > varId ( ) ! = varid )
2009-08-10 22:04:28 +02:00
return Malloc ;
2009-01-15 21:34:39 +01:00
// Does tok2 point on "g_malloc", "g_strdup", ..
2009-05-21 12:26:44 +02:00
static const char * const gmallocfunc [ ] = { " g_new " ,
" g_new0 " ,
" g_try_new " ,
" g_try_new0 " ,
" g_malloc " ,
" g_malloc0 " ,
" g_try_malloc " ,
" g_try_malloc0 " ,
" g_strdup " ,
" g_strndup " ,
0
} ;
2010-04-02 07:30:58 +02:00
for ( unsigned int i = 0 ; gmallocfunc [ i ] ; i + + )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = gmallocfunc [ i ] )
2009-01-15 21:34:39 +01:00
return gMalloc ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " new %type% [;()] " ) | |
Token : : Match ( tok2 , " new ( std :: nothrow ) %type% [;()] " ) | |
Token : : Match ( tok2 , " new ( nothrow ) %type% [;()] " ) )
2009-01-15 21:34:39 +01:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " new %type% [ " ) | |
Token : : Match ( tok2 , " new ( std :: nothrow ) %type% [ " ) | |
Token : : Match ( tok2 , " new ( nothrow ) %type% [ " ) )
2009-01-31 14:57:27 +01:00
return NewArray ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " fopen|tmpfile ( " ) )
2009-05-21 12:16:42 +02:00
return File ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " open|openat|creat|mkstemp|mkostemp ( " ) )
2010-01-26 20:10:52 +01:00
{
// is there a user function with this name?
2010-04-02 07:30:58 +02:00
if ( tokenizer & & Token : : findmatch ( tokenizer - > tokens ( ) , ( " %type% *|&| " + tok2 - > str ( ) ) . c_str ( ) ) )
2010-01-26 20:10:52 +01:00
return No ;
2009-06-21 17:01:43 +02:00
return Fd ;
2010-01-26 20:10:52 +01:00
}
2009-06-21 17:01:43 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " popen ( " ) )
2009-05-21 12:16:42 +02:00
return Pipe ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " opendir|fdopendir ( " ) )
2009-05-22 09:24:03 +02:00
return Dir ;
2009-01-15 21:34:39 +01:00
return No ;
}
2009-08-19 19:42:07 +02:00
2009-08-25 21:25:27 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getReallocationType ( const Token * tok2 , unsigned int varid ) const
2009-01-15 21:34:39 +01:00
{
// What we may have...
// * var = (char *)realloc(..;
2010-04-02 07:30:58 +02:00
if ( tok2 & & tok2 - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
{
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 ? tok2 - > next ( ) : NULL ;
}
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-01-15 21:34:39 +01:00
return No ;
2010-05-10 18:11:02 +02:00
if ( varid > 0 & & ! Token : : Match ( tok2 , " %var% ( %varid% [,)] " , varid ) )
2009-08-18 20:49:08 +02:00
return No ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " realloc " )
2009-01-15 21:34:39 +01:00
return Malloc ;
// GTK memory reallocation..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " g_realloc|g_try_realloc|g_renew|g_try_renew " ) )
2009-01-15 21:34:39 +01:00
return gMalloc ;
return No ;
}
2009-08-25 21:25:27 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getDeallocationType ( const Token * tok , unsigned int varid ) const
2009-08-19 19:42:07 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete %varid% ; " , varid ) )
2009-08-19 19:42:07 +02:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete [ ] %varid% ; " , varid ) )
2009-08-19 19:42:07 +02:00
return NewArray ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete ( %varid% ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete [ ] ( %varid% ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return NewArray ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " free ( %varid% ) ; " , varid ) | |
Token : : Match ( tok , " kfree ( %varid% ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return Malloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " g_free ( %varid% ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return gMalloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " fclose ( %varid% ) " , varid ) | |
Token : : Match ( tok , " fcloseall ( ) " ) )
2009-08-19 19:42:07 +02:00
return File ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " close ( %varid% ) " , varid ) )
2009-08-19 19:42:07 +02:00
return Fd ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " pclose ( %varid% ) " , varid ) )
2009-08-19 19:42:07 +02:00
return Pipe ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " closedir ( %varid% ) " , varid ) )
2009-08-19 19:42:07 +02:00
return Dir ;
return No ;
}
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getDeallocationType ( const Token * tok , const char * varnames [ ] ) const
2009-01-15 21:34:39 +01:00
{
int i = 0 ;
std : : string names ;
2010-04-02 07:30:58 +02:00
while ( varnames [ i ] )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( i > 0 )
2009-01-15 21:34:39 +01:00
names + = " . " ;
names + = varnames [ i ] ;
i + + ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " delete " + names + " ; " ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " delete [ ] " + names + " ; " ) . c_str ( ) ) )
2009-01-31 14:57:27 +01:00
return NewArray ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " delete ( " + names + " ) ; " ) . c_str ( ) ) )
2009-02-14 07:54:23 +01:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " delete [ ] ( " + names + " ) ; " ) . c_str ( ) ) )
2009-02-14 07:54:23 +01:00
return NewArray ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " free ( " + names + " ) ; " ) . c_str ( ) ) | |
Token : : simpleMatch ( tok , std : : string ( " kfree ( " + names + " ) ; " ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return Malloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " g_free ( " + names + " ) ; " ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return gMalloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " fclose ( " + names + " ) " ) . c_str ( ) ) | |
Token : : simpleMatch ( tok , " fcloseall ( ) " ) )
2009-05-21 12:16:42 +02:00
return File ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " close ( " + names + " ) " ) . c_str ( ) ) )
2009-06-21 17:01:43 +02:00
return Fd ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " pclose ( " + names + " ) " ) . c_str ( ) ) )
2009-05-21 12:16:42 +02:00
return Pipe ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , std : : string ( " closedir ( " + names + " ) " ) . c_str ( ) ) )
2009-05-22 09:24:03 +02:00
return Dir ;
2009-01-15 21:34:39 +01:00
return No ;
}
//--------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
//--------------------------------------------------------------------------
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : memoryLeak ( const Token * tok , const std : : string & varname , AllocType alloctype )
2009-06-08 20:20:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( alloctype = = CheckMemoryLeak : : File | |
alloctype = = CheckMemoryLeak : : Pipe | |
alloctype = = CheckMemoryLeak : : Fd | |
alloctype = = CheckMemoryLeak : : Dir )
2010-05-16 19:55:16 +02:00
resourceLeakError ( tok , varname . c_str ( ) ) ;
2009-06-08 20:20:43 +02:00
else
2010-05-16 19:55:16 +02:00
memleakError ( tok , varname . c_str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
//---------------------------------------------------------------------------
2009-08-04 21:36:55 +02:00
void CheckMemoryLeak : : reportErr ( const Token * tok , Severity : : e severity , const std : : string & id , const std : : string & msg ) const
2009-07-13 15:07:26 +02:00
{
2009-08-04 21:36:55 +02:00
std : : list < const Token * > callstack ;
2009-07-13 15:07:26 +02:00
2010-04-02 07:30:58 +02:00
if ( tok )
2009-08-04 21:36:55 +02:00
callstack . push_back ( tok ) ;
2009-07-13 15:07:26 +02:00
2009-08-04 21:36:55 +02:00
reportErr ( callstack , severity , id , msg ) ;
2009-07-13 15:07:26 +02:00
}
2009-08-04 21:36:55 +02:00
void CheckMemoryLeak : : reportErr ( const std : : list < const Token * > & callstack , Severity : : e severity , const std : : string & id , const std : : string & msg ) const
2009-07-13 15:07:26 +02:00
{
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > locations ;
2009-06-08 20:20:43 +02:00
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = callstack . begin ( ) ; it ! = callstack . end ( ) ; + + it )
2009-07-13 15:07:26 +02:00
{
2009-12-22 21:56:00 +01:00
const Token * const tok = * it ;
2009-07-13 15:07:26 +02:00
ErrorLogger : : ErrorMessage : : FileLocation loc ;
2009-12-22 21:56:00 +01:00
loc . line = tok - > linenr ( ) ;
loc . file = tokenizer - > file ( tok ) ;
2009-07-13 15:07:26 +02:00
locations . push_back ( loc ) ;
}
2009-08-04 21:36:55 +02:00
const ErrorLogger : : ErrorMessage errmsg ( locations , Severity : : stringify ( severity ) , msg , id ) ;
2010-04-02 07:30:58 +02:00
if ( errorLogger )
2009-08-04 21:36:55 +02:00
errorLogger - > reportErr ( errmsg ) ;
else
std : : cout < < errmsg . toXML ( ) < < std : : endl ;
2009-07-13 15:07:26 +02:00
}
2009-06-08 20:20:43 +02:00
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : memleakError ( const Token * tok , const std : : string & varname )
2009-06-08 20:20:43 +02:00
{
2010-05-16 19:55:16 +02:00
reportErr ( tok , Severity : : error , " memleak " , " Memory leak: " + varname ) ;
2009-06-08 20:20:43 +02:00
}
2010-05-18 07:46:48 +02:00
void CheckMemoryLeak : : memleakUponReallocFailureError ( const Token * tok , const std : : string & varname )
{
reportErr ( tok , Severity : : error , " memleakOnRealloc " , " Memory leak: \" " + varname + " \" nulled but not freed upon failure " ) ;
}
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : resourceLeakError ( const Token * tok , const std : : string & varname )
2009-06-08 20:20:43 +02:00
{
2009-10-03 21:46:22 +02:00
std : : string errmsg ( " Resource leak " ) ;
2010-04-02 07:30:58 +02:00
if ( ! varname . empty ( ) )
2009-10-03 21:46:22 +02:00
errmsg + = " : " + varname ;
2010-05-16 19:55:16 +02:00
reportErr ( tok , Severity : : error , " resourceLeak " , errmsg ) ;
2009-06-08 20:20:43 +02:00
}
void CheckMemoryLeak : : deallocDeallocError ( const Token * tok , const std : : string & varname )
{
2009-08-04 21:36:55 +02:00
reportErr ( tok , Severity : : error , " deallocDealloc " , " Deallocating a deallocated pointer: " + varname ) ;
2009-06-08 20:20:43 +02:00
}
void CheckMemoryLeak : : deallocuseError ( const Token * tok , const std : : string & varname )
{
2009-08-04 21:36:55 +02:00
reportErr ( tok , Severity : : error , " deallocuse " , " Dereferencing ' " + varname + " ' after it is deallocated / released " ) ;
2009-06-08 20:20:43 +02:00
}
void CheckMemoryLeak : : mismatchSizeError ( const Token * tok , const std : : string & sz )
{
2009-08-04 21:36:55 +02:00
reportErr ( tok , Severity : : error , " mismatchSize " , " The given size " + sz + " is mismatching " ) ;
2009-06-08 20:20:43 +02:00
}
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : mismatchAllocDealloc ( const std : : list < const Token * > & callstack , const std : : string & varname )
2009-06-08 20:20:43 +02:00
{
2010-05-16 19:55:16 +02:00
reportErr ( callstack , Severity : : error , " mismatchAllocDealloc " , " Mismatching allocation and deallocation: " + varname ) ;
2009-06-08 20:20:43 +02:00
}
2009-06-15 17:44:59 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : functionReturnType ( const Token * tok ) const
{
// Locate the start of the function..
unsigned int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
while ( tok )
2009-06-15 17:44:59 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " | | tok - > str ( ) = = " } " )
2009-06-15 17:44:59 +02:00
return No ;
2009-06-08 20:20:43 +02:00
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-06-15 17:44:59 +02:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel ! = 0 )
2009-06-15 17:44:59 +02:00
return No ;
+ + parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-06-15 17:44:59 +02:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel ! = 1 )
2009-06-15 17:44:59 +02:00
return No ;
break ;
}
tok = tok - > next ( ) ;
}
2009-06-15 21:13:39 +02:00
// Is this the start of a function?
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " ) const| { " ) )
2009-06-15 21:13:39 +02:00
return No ;
2010-04-02 07:30:58 +02:00
while ( tok - > str ( ) ! = " { " )
2009-06-15 21:13:39 +02:00
tok = tok - > next ( ) ;
2010-05-09 13:46:13 +02:00
// Get return pointer..
2009-08-19 19:42:07 +02:00
unsigned int varid = 0 ;
2010-05-09 13:46:13 +02:00
unsigned int indentlevel = 0 ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
if ( indentlevel < = 1 )
return No ;
2009-06-15 21:13:39 +02:00
}
2010-05-09 13:46:13 +02:00
if ( Token : : Match ( tok2 , " return %var% ; " ) )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
if ( indentlevel ! = 1 )
2009-06-15 21:13:39 +02:00
return No ;
2010-05-09 13:46:13 +02:00
varid = tok2 - > next ( ) - > varId ( ) ;
break ;
2009-06-15 21:13:39 +02:00
}
2010-05-09 13:46:13 +02:00
else if ( tok2 - > str ( ) = = " return " )
2010-04-24 20:40:57 +02:00
{
2010-05-09 13:46:13 +02:00
AllocType allocType = getAllocationType ( tok2 - > next ( ) , 0 ) ;
if ( allocType ! = No )
return allocType ;
allocType = getReallocationType ( tok2 - > next ( ) , 0 ) ;
if ( allocType ! = No )
return allocType ;
2010-04-24 20:40:57 +02:00
}
2010-05-09 13:46:13 +02:00
}
2010-04-24 20:40:57 +02:00
2010-05-09 13:46:13 +02:00
// Not returning pointer value..
if ( varid = = 0 )
return No ;
// Check if return pointer is allocated..
AllocType allocType = No ;
while ( 0 ! = ( tok = tok - > next ( ) ) )
{
if ( Token : : Match ( tok , " %varid% = " , varid ) )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
allocType = getAllocationType ( tok - > tokAt ( 2 ) , varid ) ;
if ( allocType = = No )
{
allocType = getReallocationType ( tok - > tokAt ( 2 ) , varid ) ;
}
if ( allocType ! = No )
2009-06-15 21:13:39 +02:00
return allocType ;
}
2010-05-09 13:46:13 +02:00
if ( tok - > str ( ) = = " return " )
return allocType ;
2009-06-15 21:13:39 +02:00
}
2009-06-15 17:44:59 +02:00
return No ;
}
2009-06-08 20:20:43 +02:00
2009-11-14 09:06:28 +01:00
void CheckMemoryLeakInFunction : : parse_noreturn ( )
{
2009-11-15 09:53:38 +01:00
noreturn . insert ( " exit " ) ;
noreturn . insert ( " _exit " ) ;
noreturn . insert ( " _Exit " ) ;
noreturn . insert ( " abort " ) ;
noreturn . insert ( " err " ) ;
noreturn . insert ( " verr " ) ;
noreturn . insert ( " errx " ) ;
noreturn . insert ( " verrx " ) ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-11-14 09:06:28 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-11-14 09:06:28 +01:00
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-11-14 09:06:28 +01:00
{
2010-02-20 08:53:33 +01:00
const std : : string function_name ( ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) ) ? tok - > strAt ( - 1 ) . c_str ( ) : " " ) ;
2009-11-14 09:06:28 +01:00
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! function_name . empty ( ) & & Token : : simpleMatch ( tok , " ) { " ) )
2009-11-14 09:06:28 +01:00
{
// parse this function to check if it contains an "exit" call..
unsigned int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-11-14 09:06:28 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-11-14 09:06:28 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2009-11-14 09:06:28 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 1 )
2009-11-14 09:06:28 +01:00
break ;
- - indentlevel ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] exit ( " ) )
2009-11-14 09:06:28 +01:00
{
noreturn . insert ( function_name ) ;
break ;
}
}
}
}
}
}
2009-08-25 21:25:27 +02:00
bool CheckMemoryLeakInFunction : : matchFunctionsThatReturnArg ( const Token * tok , unsigned int varid ) const
2009-06-08 20:20:43 +02:00
{
2009-08-19 19:42:07 +02:00
return Token : : Match ( tok , " ; %varid% = strcat|memcpy|memmove|strcpy ( %varid% , " , varid ) ;
2009-06-08 20:20:43 +02:00
}
2009-08-25 21:25:27 +02:00
bool CheckMemoryLeakInFunction : : notvar ( const Token * tok , unsigned int varid , bool endpar ) const
2009-06-08 20:20:43 +02:00
{
const std : : string end ( endpar ? " &&|) " : " [;)&|] " ) ;
2009-08-19 19:42:07 +02:00
return bool ( Token : : Match ( tok , ( " ! %varid% " + end ) . c_str ( ) , varid ) | |
Token : : Match ( tok , ( " ! ( %varid% ) " + end ) . c_str ( ) , varid ) ) ;
2009-06-08 20:20:43 +02:00
}
2009-06-12 17:31:29 +02:00
static int countParameters ( const Token * tok )
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " %var% ( " ) )
2009-06-12 17:31:29 +02:00
return - 1 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " void| ) " ) )
2009-06-12 17:31:29 +02:00
return 0 ;
int numpar = 1 ;
int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-06-12 17:31:29 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-06-12 17:31:29 +02:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-06-12 17:31:29 +02:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel < = 1 )
2009-06-12 17:31:29 +02:00
return numpar ;
- - parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( parlevel = = 1 & & tok - > str ( ) = = " , " )
2009-06-12 17:31:29 +02:00
+ + numpar ;
}
return - 1 ;
}
2009-06-08 20:20:43 +02:00
2010-02-14 19:58:17 +01:00
bool CheckMemoryLeakInFunction : : test_white_list ( const std : : string & funcname )
2010-01-18 21:34:11 +01:00
{
2010-04-06 20:35:21 +02:00
return ( std : : bsearch ( funcname . c_str ( ) , call_func_white_list ,
sizeof ( call_func_white_list ) / sizeof ( call_func_white_list [ 0 ] ) ,
sizeof ( call_func_white_list [ 0 ] ) , call_func_white_list_compare ) ! = NULL ) ;
2010-01-18 21:34:11 +01:00
}
2010-05-16 19:55:16 +02:00
const char * CheckMemoryLeakInFunction : : call_func ( const Token * tok , std : : list < const Token * > callstack , const unsigned int varid , AllocType & alloctype , AllocType & dealloctype , unsigned int sz )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( test_white_list ( tok - > str ( ) ) )
2009-02-14 07:54:23 +01:00
return 0 ;
2010-04-02 07:30:58 +02:00
if ( noreturn . find ( tok - > str ( ) ) ! = noreturn . end ( ) )
2009-11-14 09:06:28 +01:00
return " exit " ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & ( getAllocationType ( tok , varid ) ! = No | | getReallocationType ( tok , varid ) ! = No | | getDeallocationType ( tok , varid ) ! = No ) )
2009-01-15 21:34:39 +01:00
return 0 ;
2010-04-02 07:30:58 +02:00
if ( callstack . size ( ) > 2 )
2009-01-15 21:34:39 +01:00
return " dealloc_ " ;
2009-02-08 12:59:04 +01:00
const std : : string funcname ( tok - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = callstack . begin ( ) ; it ! = callstack . end ( ) ; + + it )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ( * it ) & & ( * it ) - > str ( ) = = funcname )
2009-01-15 21:34:39 +01:00
return " recursive " ;
}
callstack . push_back ( tok ) ;
2009-06-15 17:44:59 +02:00
2009-10-03 21:46:22 +02:00
// lock/unlock..
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-10-03 21:46:22 +02:00
{
const Token * ftok = _tokenizer - > getFunctionTokenByName ( funcname . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
2009-10-03 21:46:22 +02:00
ftok = ftok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! ftok )
2009-10-03 21:46:22 +02:00
return 0 ;
2010-05-16 19:55:16 +02:00
Token * func = getcode ( ftok - > tokAt ( 1 ) , callstack , 0 , alloctype , dealloctype , false , 1 ) ;
simplifycode ( func ) ;
2009-10-03 21:46:22 +02:00
const char * ret = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( func , " ; alloc ; } " ) )
2009-10-03 21:46:22 +02:00
ret = " alloc " ;
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( func , " ; dealloc ; } " ) )
2009-10-03 21:46:22 +02:00
ret = " dealloc " ;
Tokenizer : : deleteTokens ( func ) ;
return ret ;
}
2009-06-15 17:44:59 +02:00
// Check if this is a function that allocates memory..
{
2009-07-05 22:16:43 +02:00
const Token * ftok = _tokenizer - > getFunctionTokenByName ( funcname . c_str ( ) ) ;
2009-06-15 17:44:59 +02:00
AllocType a = functionReturnType ( ftok ) ;
2010-04-02 07:30:58 +02:00
if ( a ! = No )
2010-05-09 13:46:13 +02:00
{
if ( alloctype = = No )
alloctype = a ;
else if ( alloctype ! = a )
alloctype = Many ;
2009-06-15 17:44:59 +02:00
return " alloc " ;
2010-05-09 13:46:13 +02:00
}
2009-06-15 17:44:59 +02:00
}
2009-01-15 21:34:39 +01:00
2009-06-12 17:31:29 +02:00
// how many parameters is there in the function call?
int numpar = countParameters ( tok ) ;
2010-04-02 07:30:58 +02:00
if ( numpar < = 0 )
2009-06-12 17:31:29 +02:00
return " callfunc " ;
2009-01-15 21:34:39 +01:00
int par = 1 ;
int parlevel = 0 ;
2009-10-12 21:36:28 +02:00
const bool dot ( tok - > previous ( ) - > str ( ) = = " . " ) ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-01-15 21:34:39 +01:00
{
- - parlevel ;
2010-04-02 07:30:58 +02:00
if ( parlevel < 1 )
2009-02-08 12:59:04 +01:00
{
2010-04-10 14:05:33 +02:00
return ( _settings & & _settings - > inconclusive ) ? 0 : " callfunc " ;
2009-02-08 12:59:04 +01:00
}
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( parlevel = = 1 )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " , " )
2009-01-15 21:34:39 +01:00
+ + par ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " [,()] %varid% [,()] " , varid ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( dot )
2009-10-12 21:36:28 +02:00
return " use " ;
2009-07-05 22:16:43 +02:00
const Token * ftok = _tokenizer - > getFunctionTokenByName ( funcname . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! ftok )
2009-06-23 20:37:34 +02:00
return " use " ;
2009-06-12 17:31:29 +02:00
// how many parameters does the function want?
2010-04-02 07:30:58 +02:00
if ( numpar ! = countParameters ( ftok ) )
2009-06-12 17:31:29 +02:00
return " recursive " ;
2009-01-15 21:34:39 +01:00
const char * parname = Tokenizer : : getParameterName ( ftok , par ) ;
2010-04-02 07:30:58 +02:00
if ( ! parname )
2009-01-15 21:34:39 +01:00
return " recursive " ;
2009-08-19 19:42:07 +02:00
unsigned int parameterVarid = 0 ;
{
const Token * partok = Token : : findmatch ( ftok , parname ) ;
2010-04-02 07:30:58 +02:00
if ( partok )
2009-08-19 19:42:07 +02:00
parameterVarid = partok - > varId ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( parameterVarid = = 0 )
2009-08-19 19:42:07 +02:00
return " recursive " ;
2009-01-15 21:34:39 +01:00
// Check if the function deallocates the variable..
2010-04-02 07:30:58 +02:00
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
2009-01-15 21:34:39 +01:00
ftok = ftok - > next ( ) ;
2010-05-16 19:55:16 +02:00
Token * func = getcode ( ftok - > tokAt ( 1 ) , callstack , parameterVarid , alloctype , dealloctype , false , sz ) ;
2010-02-06 22:35:36 +01:00
//simplifycode(func, all);
2009-01-15 21:34:39 +01:00
const Token * func_ = func ;
2010-04-02 07:30:58 +02:00
while ( func_ & & func_ - > str ( ) = = " ; " )
2009-01-15 21:34:39 +01:00
func_ = func_ - > next ( ) ;
const char * ret = 0 ;
2009-07-14 08:17:12 +02:00
/** @todo handle "goto" */
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( func_ , " dealloc " ) )
2009-01-15 21:34:39 +01:00
ret = " dealloc " ;
2010-04-02 07:30:58 +02:00
else if ( Token : : findmatch ( func_ , " use " ) )
2009-01-15 21:34:39 +01:00
ret = " use " ;
2010-04-02 07:30:58 +02:00
else if ( Token : : findmatch ( func_ , " &use " ) )
2009-01-15 21:34:39 +01:00
ret = " &use " ;
Tokenizer : : deleteTokens ( func ) ;
return ret ;
}
}
}
return NULL ;
}
2009-02-04 07:11:36 +01:00
2009-01-15 21:34:39 +01:00
2010-05-16 19:55:16 +02:00
Token * CheckMemoryLeakInFunction : : getcode ( const Token * tok , std : : list < const Token * > callstack , const unsigned int varid , CheckMemoryLeak : : AllocType & alloctype , CheckMemoryLeak : : AllocType & dealloctype , bool classmember , unsigned int sz )
2009-01-15 21:34:39 +01:00
{
Token * rethead = 0 , * rettail = 0 ;
# define addtoken(_str) \
{ \
if ( rettail ) \
{ \
rettail - > insertToken ( _str ) ; \
rettail = rettail - > next ( ) ; \
} \
else \
{ \
2010-01-06 20:19:27 +01:00
rethead = new Token ( 0 ) ; \
2009-01-15 21:34:39 +01:00
rettail = rethead ; \
rettail - > str ( _str ) ; \
} \
\
rettail - > linenr ( tok - > linenr ( ) ) ; \
rettail - > fileIndex ( tok - > fileIndex ( ) ) ; \
}
// The first token should be ";"
addtoken ( " ; " ) ;
bool isloop = false ;
int indentlevel = 0 ;
int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
{
addtoken ( " { " ) ;
+ + indentlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-15 21:34:39 +01:00
{
addtoken ( " } " ) ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 0 )
2009-01-15 21:34:39 +01:00
break ;
- - indentlevel ;
}
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-01-15 21:34:39 +01:00
- - parlevel ;
isloop & = ( parlevel > 0 ) ;
2010-04-02 07:30:58 +02:00
if ( parlevel = = 0 & & tok - > str ( ) = = " ; " )
2009-01-15 21:34:39 +01:00
addtoken ( " ; " ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-08-29 17:33:57 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! callstack . empty ( ) & & Token : : Match ( tok , " [;{}] __cppcheck_lock|__cppcheck_unlock ( ) ; " ) )
2009-08-29 07:02:36 +02:00
{
2009-10-03 21:46:22 +02:00
// Type of leak = Resource leak
alloctype = dealloctype = CheckMemoryLeak : : File ;
2010-04-02 07:30:58 +02:00
if ( tok - > next ( ) - > str ( ) = = " __cppcheck_lock " )
2009-10-03 21:46:22 +02:00
{
addtoken ( " alloc " ) ;
}
else
2009-08-29 07:26:32 +02:00
{
2009-10-03 21:46:22 +02:00
addtoken ( " dealloc " ) ;
2009-08-29 07:26:32 +02:00
}
2009-10-03 21:46:22 +02:00
tok = tok - > tokAt ( 3 ) ;
continue ;
2009-08-29 07:02:36 +02:00
}
2009-10-03 21:46:22 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) )
2009-08-29 07:02:36 +02:00
{
2009-10-03 21:46:22 +02:00
addtoken ( " if " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
2009-08-29 07:02:36 +02:00
}
2009-10-03 21:46:22 +02:00
}
else
{
// var = strcpy|.. ( var ,
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [;{}] %varid% = memcpy|memmove|memset|strcpy|strncpy|strcat|strncat ( %varid% , " , varid ) )
2009-02-07 11:54:39 +01:00
{
2009-10-03 21:46:22 +02:00
tok = tok - > tokAt ( 4 ) - > link ( ) ;
continue ;
2009-02-07 11:54:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > previous ( ) , " [(;{}] %varid% = " , varid ) | |
Token : : Match ( tok , " asprintf ( & %varid% , " , varid ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
CheckMemoryLeak : : AllocType alloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " asprintf ( " ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
// todo: check how the return value is used.
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok - > previous ( ) , " [;{}] " ) )
2009-10-03 21:46:22 +02:00
{
Tokenizer : : deleteTokens ( rethead ) ;
return 0 ;
}
alloc = Malloc ;
tok = tok - > next ( ) - > link ( ) ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
else
{
alloc = getAllocationType ( tok - > tokAt ( 2 ) , varid ) ;
}
bool realloc = false ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( sz > 1 & &
Token : : Match ( tok - > tokAt ( 2 ) , " malloc ( %num% ) " ) & &
( MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) % sz ) ! = 0 )
2009-10-03 21:46:22 +02:00
{
mismatchSizeError ( tok - > tokAt ( 4 ) , tok - > strAt ( 4 ) ) ;
}
2010-04-02 07:30:58 +02:00
if ( alloc = = CheckMemoryLeak : : No )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
alloc = getReallocationType ( tok - > tokAt ( 2 ) , varid ) ;
2010-04-02 07:30:58 +02:00
if ( alloc ! = CheckMemoryLeak : : No )
2009-01-31 14:57:27 +01:00
{
2009-10-03 21:46:22 +02:00
addtoken ( " realloc " ) ;
addtoken ( " ; " ) ;
realloc = true ;
tok = tok - > tokAt ( 2 ) ;
continue ;
}
}
2009-02-20 07:28:18 +01:00
2010-05-16 07:15:31 +02:00
// don't check classes..
2010-04-02 07:30:58 +02:00
if ( alloc = = CheckMemoryLeak : : New )
2009-10-03 21:46:22 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " new %type% [(;] " ) )
2009-10-03 21:46:22 +02:00
{
2010-04-02 07:30:58 +02:00
if ( isclass ( _tokenizer , tok - > tokAt ( 3 ) ) )
2009-10-03 21:46:22 +02:00
{
2010-05-16 07:15:31 +02:00
alloc = No ;
2009-02-20 07:28:18 +01:00
}
2009-01-31 14:57:27 +01:00
}
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( alloc ! = No )
2009-10-03 21:46:22 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! realloc )
2009-10-03 21:46:22 +02:00
addtoken ( " alloc " ) ;
2009-02-06 07:11:47 +01:00
2010-04-02 07:30:58 +02:00
if ( alloctype ! = No & & alloctype ! = alloc )
2009-10-03 21:46:22 +02:00
alloc = Many ;
2009-02-06 07:11:47 +01:00
2010-04-02 07:30:58 +02:00
if ( alloc ! = Many & & dealloctype ! = No & & dealloctype ! = Many & & dealloctype ! = alloc )
2009-10-03 21:46:22 +02:00
{
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) - > str ( ) ) ;
2009-10-03 21:46:22 +02:00
callstack . pop_back ( ) ;
}
alloctype = alloc ;
}
// assignment..
else
{
// is the pointer in rhs?
bool rhs = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-10-03 21:46:22 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ; " )
2009-10-03 21:46:22 +02:00
break ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [=+] %varid% " , varid ) )
2009-10-03 21:46:22 +02:00
{
rhs = true ;
break ;
}
}
addtoken ( ( rhs ? " use " : " assign " ) ) ;
}
2009-01-25 21:57:34 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > previous ( ) , " [;{})=] %var% " ) | |
Token : : Match ( tok - > previous ( ) , " |= %var% " ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
AllocType dealloc = getDeallocationType ( tok , varid ) ;
2010-01-07 21:36:51 +01:00
2010-04-02 07:30:58 +02:00
if ( dealloc ! = No & & tok - > str ( ) = = " fcloseall " & & alloctype ! = dealloc )
2010-01-07 21:36:51 +01:00
dealloc = No ;
2010-04-02 07:30:58 +02:00
else if ( dealloc ! = No )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
addtoken ( " dealloc " ) ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( dealloctype ! = No & & dealloctype ! = dealloc )
2009-10-03 21:46:22 +02:00
dealloc = Many ;
2010-04-02 07:30:58 +02:00
if ( dealloc ! = Many & & alloctype ! = No & & alloctype ! = Many & & alloctype ! = dealloc )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) - > str ( ) ) ;
2009-10-03 21:46:22 +02:00
callstack . pop_back ( ) ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
dealloctype = dealloc ;
continue ;
2009-01-15 21:34:39 +01:00
}
}
2009-10-03 21:46:22 +02:00
// if else switch
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " if " )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( alloctype = = Fd )
2009-02-01 16:47:36 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( 0 <= %varid% ) " , varid ) | |
Token : : Match ( tok , " if ( %varid% != -1 ) " , varid ) )
2009-10-03 21:46:22 +02:00
{
addtoken ( " if(var) " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " if ( %varid% == -1 ) " , varid ) | |
Token : : Match ( tok , " if ( %varid% < 0 ) " , varid ) )
2009-10-03 21:46:22 +02:00
{
addtoken ( " if(!var) " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2009-02-01 16:47:36 +01:00
}
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( %varid% ) " , varid ) )
2009-08-29 09:18:21 +02:00
{
addtoken ( " if(var) " ) ;
2009-10-03 21:46:22 +02:00
// Make sure the "use" will not be added
2009-08-29 09:18:21 +02:00
tok = tok - > next ( ) - > link ( ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok , " if ( " ) & & notvar ( tok - > tokAt ( 2 ) , varid , true ) )
2009-08-29 09:18:21 +02:00
{
addtoken ( " if(!var) " ) ;
}
2009-10-03 21:46:22 +02:00
else
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
// Check if the condition depends on var somehow..
bool dep = false ;
2010-04-06 22:17:23 +02:00
int innerParlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2010-04-06 22:17:23 +02:00
+ + innerParlevel ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ) " )
2009-10-03 21:46:22 +02:00
{
2010-04-06 22:17:23 +02:00
- - innerParlevel ;
if ( innerParlevel < = 0 )
2009-10-03 21:46:22 +02:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " close|pclose|fclose|closedir ( %varid% ) " , varid ) )
2009-10-03 21:46:22 +02:00
{
addtoken ( " dealloc " ) ;
addtoken ( " ; " ) ;
dep = true ;
2009-01-15 21:34:39 +01:00
break ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
if ( alloctype = = Fd & & Token : : Match ( tok2 , " %varid% !=|>= " , varid ) )
2009-10-03 21:46:22 +02:00
{
dep = true ;
}
2010-04-06 22:17:23 +02:00
if ( innerParlevel > 0 & & Token : : Match ( tok2 , " ! %varid% " , varid ) )
2010-03-13 17:11:48 +01:00
{
dep = true ;
break ;
}
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( ! %varid% && " , varid ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
addtoken ( " if(!var) " ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > next ( ) & &
tok - > next ( ) - > link ( ) & &
Token : : Match ( tok - > next ( ) - > link ( ) - > tokAt ( - 3 ) , " && ! %varid% " , varid ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
addtoken ( " if(!var) " ) ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
else
2009-08-29 09:18:21 +02:00
{
2009-10-03 21:46:22 +02:00
addtoken ( ( dep ? " ifv " : " if " ) ) ;
2009-08-29 09:18:21 +02:00
}
2010-03-13 17:11:48 +01:00
2010-04-06 14:23:17 +02:00
tok = tok - > next ( ) ;
if ( tok - > link ( ) )
tok = tok - > link ( ) ;
2009-01-15 21:34:39 +01:00
}
}
}
2010-04-02 07:30:58 +02:00
if ( ( tok - > str ( ) = = " else " ) | | ( tok - > str ( ) = = " switch " ) )
2009-01-15 21:34:39 +01:00
{
2009-05-03 20:10:59 +02:00
addtoken ( tok - > str ( ) . c_str ( ) ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( ( tok - > str ( ) = = " case " ) )
2009-01-15 21:34:39 +01:00
{
addtoken ( " case " ) ;
addtoken ( " ; " ) ;
}
2010-04-02 07:30:58 +02:00
else if ( ( tok - > str ( ) = = " default " ) )
2009-01-15 21:34:39 +01:00
{
addtoken ( " default " ) ;
addtoken ( " ; " ) ;
}
// Loops..
2010-04-02 07:30:58 +02:00
else if ( ( tok - > str ( ) = = " for " ) | | ( tok - > str ( ) = = " while " ) )
2009-01-15 21:34:39 +01:00
{
2010-01-24 21:48:39 +01:00
isloop = true ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " while ( true ) " ) | |
Token : : simpleMatch ( tok , " for ( ; ; ) " ) )
2009-09-27 21:49:07 +02:00
{
addtoken ( " while1 " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-01-24 21:48:39 +01:00
2010-04-02 07:30:58 +02:00
else if ( alloctype = = Fd & & varid )
2010-01-24 21:48:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " while ( 0 <= %varid% ) " , varid ) | |
Token : : Match ( tok , " while ( %varid% != -1 ) " , varid ) )
2010-01-24 21:48:39 +01:00
{
addtoken ( " while(var) " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " while ( %varid% == -1 ) " , varid ) | |
Token : : Match ( tok , " while ( %varid% < 0 ) " , varid ) )
2010-01-24 21:48:39 +01:00
{
addtoken ( " while(!var) " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : Match ( tok , " while ( %varid% ) " , varid ) )
2010-01-24 21:48:39 +01:00
{
addtoken ( " while(var) " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : simpleMatch ( tok , " while ( " ) & & notvar ( tok - > tokAt ( 2 ) , varid , true ) )
2010-01-24 21:48:39 +01:00
{
addtoken ( " while(!var) " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2009-01-15 21:34:39 +01:00
addtoken ( " loop " ) ;
}
2010-04-02 07:30:58 +02:00
else if ( ( tok - > str ( ) = = " do " ) )
2009-01-15 21:34:39 +01:00
{
addtoken ( " do " ) ;
}
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & isloop & & notvar ( tok , varid ) )
2009-10-03 21:46:22 +02:00
{
2009-01-15 21:34:39 +01:00
addtoken ( " !var " ) ;
2009-10-03 21:46:22 +02:00
}
2009-01-15 21:34:39 +01:00
// continue / break..
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " continue " )
2009-10-03 21:46:22 +02:00
{
2009-01-15 21:34:39 +01:00
addtoken ( " continue " ) ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " break " )
2009-10-03 21:46:22 +02:00
{
2009-01-15 21:34:39 +01:00
addtoken ( " break " ) ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " goto " )
2009-01-15 21:34:39 +01:00
{
addtoken ( " goto " ) ;
}
// Return..
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " return " )
2009-01-15 21:34:39 +01:00
{
addtoken ( " return " ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-10-03 21:46:22 +02:00
{
addtoken ( " ; " ) ;
2010-04-02 07:30:58 +02:00
while ( tok & & tok - > str ( ) ! = " ; " )
2009-10-03 21:46:22 +02:00
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-10-03 21:46:22 +02:00
break ;
continue ;
}
2009-04-28 20:01:35 +02:00
// Returning a auto_ptr of this allocated variable..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) , " std :: auto_ptr < " ) )
2009-04-28 20:01:35 +02:00
{
const Token * tok2 = tok - > tokAt ( 5 ) ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " > " )
2009-04-28 20:01:35 +02:00
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " > ( %varid% ) " , varid ) )
2009-04-28 20:01:35 +02:00
{
addtoken ( " use " ) ;
tok = tok2 - > tokAt ( 3 ) ;
}
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : Match ( tok , " return &| %varid% " , varid ) )
2009-04-28 20:01:35 +02:00
{
2009-01-15 21:34:39 +01:00
addtoken ( " use " ) ;
2009-04-28 20:01:35 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : Match ( tok , " return strcpy|strncpy|memcpy ( %varid% " , varid ) )
2009-07-24 21:55:35 +02:00
{
addtoken ( " use " ) ;
tok = tok - > tokAt ( 2 ) ;
}
else
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ; " )
2009-07-24 21:55:35 +02:00
break ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) = = varid )
2009-01-15 21:34:39 +01:00
{
addtoken ( " use " ) ;
2009-08-29 06:42:24 +02:00
tok = tok2 ;
2009-01-15 21:34:39 +01:00
break ;
}
}
}
}
// throw..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " try|throw|catch " ) )
2009-01-15 21:34:39 +01:00
addtoken ( tok - > strAt ( 0 ) ) ;
// Assignment..
2010-04-02 07:30:58 +02:00
if ( varid )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [)=] %varid% [+;)] " , varid ) | |
Token : : Match ( tok , " %var% + %varid% " , varid ) | |
Token : : Match ( tok , " %varid% +=|-= " , varid ) | |
Token : : Match ( tok , " +=|<< %varid% ; " , varid ) | |
Token : : Match ( tok , " = strcpy|strcat|memmove|memcpy ( %varid% , " , varid ) )
2009-08-25 21:44:19 +02:00
{
addtoken ( " use " ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " [ ; { } = ( , + - */ ] % varid % [ " , varid))
2009-08-25 21:44:19 +02:00
{
addtoken ( " use_ " ) ;
}
2009-01-15 21:34:39 +01:00
}
// Investigate function calls..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% ( " ) )
2009-01-15 21:34:39 +01:00
{
2009-11-15 10:30:00 +01:00
// A function call should normally be followed by ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) )
2009-11-15 10:30:00 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " if|for|while|switch " ) )
2009-11-15 10:30:00 +01:00
{
addtoken ( " exit " ) ;
addtoken ( " ; " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
}
2009-01-15 21:34:39 +01:00
// Inside class function.. if the var is passed as a parameter then
2009-01-26 19:15:44 +01:00
// just add a "::use"
// The "::use" means that a member function was probably called but it wasn't analyzed further
2010-04-02 07:30:58 +02:00
else if ( classmember )
2009-01-15 21:34:39 +01:00
{
2010-04-06 22:17:23 +02:00
int innerParlevel = 1 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2010-04-06 22:17:23 +02:00
+ + innerParlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-01-15 21:34:39 +01:00
{
2010-04-06 22:17:23 +02:00
- - innerParlevel ;
if ( innerParlevel < = 0 )
2009-01-15 21:34:39 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) = = varid )
2009-01-15 21:34:39 +01:00
{
2009-01-26 19:15:44 +01:00
addtoken ( " ::use " ) ;
2009-01-15 21:34:39 +01:00
break ;
}
}
}
else
{
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " %var% ( close|fclose|pclose ( %varid% ) ) ; " , varid ) )
2009-10-04 13:10:08 +02:00
{
addtoken ( " dealloc " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-05-16 19:55:16 +02:00
const char * str = call_func ( tok , callstack , varid , alloctype , dealloctype , sz ) ;
2010-04-02 07:30:58 +02:00
if ( str )
2009-08-02 22:30:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-10-03 21:46:22 +02:00
{
2009-08-05 21:18:16 +02:00
addtoken ( str ) ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( str ! = std : : string ( " alloc " ) | |
Token : : Match ( tok - > tokAt ( - 2 ) , " %varid% = " , varid ) )
2009-08-02 22:30:43 +02:00
{
2009-10-03 21:46:22 +02:00
addtoken ( str ) ;
2009-08-02 22:30:43 +02:00
}
}
2010-04-02 07:30:58 +02:00
else if ( varid > 0 & &
getReallocationType ( tok , varid ) ! = No & &
tok - > tokAt ( 2 ) - > varId ( ) = = varid )
2009-10-03 21:46:22 +02:00
{
addtoken ( " if " ) ;
addtoken ( " { " ) ;
addtoken ( " dealloc " ) ;
addtoken ( " ; " ) ;
addtoken ( " } " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2009-01-15 21:34:39 +01:00
}
}
// Callback..
2009-07-20 22:24:23 +02:00
bool matchFirst = Token : : Match ( tok , " ( %var% " ) ;
2010-04-02 07:30:58 +02:00
if ( matchFirst | | Token : : Match ( tok , " ( * %var% " ) )
2009-01-15 21:34:39 +01:00
{
int tokIdx = matchFirst ? 2 : 3 ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok - > tokAt ( tokIdx ) , " . %var% " ) )
2009-01-15 21:34:39 +01:00
tokIdx + = 2 ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > tokAt ( tokIdx ) , " ) ( " ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( tokIdx + 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{] " ) )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > varId ( ) = = varid )
2009-01-15 21:34:39 +01:00
{
addtoken ( " use " ) ;
break ;
}
}
}
}
// Linux lists..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " [=(,] & %varid% [.[,)] " , varid ) )
2009-01-15 21:34:39 +01:00
{
addtoken ( " &use " ) ;
}
}
return rethead ;
}
2009-06-08 20:20:43 +02:00
2010-05-16 19:55:16 +02:00
void CheckMemoryLeakInFunction : : simplifycode ( Token * tok )
2009-01-15 21:34:39 +01:00
{
// Replace "throw" that is not in a try block with "return"
int indentlevel = 0 ;
int trylevel = - 1 ;
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2009-01-15 21:34:39 +01:00
{
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < = trylevel )
2009-01-15 21:34:39 +01:00
trylevel = - 1 ;
}
2010-04-02 07:30:58 +02:00
else if ( trylevel = = - 1 & & tok2 - > str ( ) = = " try " )
2009-01-15 21:34:39 +01:00
trylevel = indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( trylevel = = - 1 & & tok2 - > str ( ) = = " throw " )
2009-01-15 21:34:39 +01:00
tok2 - > str ( " return " ) ;
}
2010-01-14 21:41:50 +01:00
// reduce "if callfunc {" => "if {"
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2010-01-14 21:41:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " if|ifv callfunc { " ) )
2010-01-14 21:41:50 +01:00
tok2 - > deleteNext ( ) ;
}
2010-04-27 20:43:31 +02:00
// remove redundant braces..
for ( Token * start = tok ; start ; start = start - > next ( ) )
{
if ( Token : : simpleMatch ( start , " ; { " ) )
{
// the "link" doesn't work here. Find the end brace..
unsigned int indent = 0 ;
for ( Token * end = start ; end ; end = end - > next ( ) )
{
if ( end - > str ( ) = = " { " )
+ + indent ;
else if ( end - > str ( ) = = " } " )
{
if ( indent < = 1 )
{
if ( indent = = 1 & & Token : : Match ( end - > previous ( ) , " [;{}] } %any% " ) )
{
start - > deleteNext ( ) ;
end - > deleteThis ( ) ;
}
break ;
}
- - indent ;
}
}
}
}
2009-01-15 21:34:39 +01:00
// reduce the code..
bool done = false ;
2010-04-02 07:30:58 +02:00
while ( ! done )
2009-01-15 21:34:39 +01:00
{
2009-06-20 13:58:30 +02:00
//tok->printOut("simplifycode loop..");
2009-01-15 21:34:39 +01:00
done = true ;
2010-01-14 21:41:50 +01:00
// simplify "while1" contents..
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2010-01-14 21:41:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 { " ) )
2010-01-14 21:41:50 +01:00
{
2010-04-06 22:17:23 +02:00
unsigned int innerIndentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( Token * tok3 = tok2 - > tokAt ( 2 ) ; tok3 ; tok3 = tok3 - > next ( ) )
2010-01-14 21:41:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2010-04-06 22:17:23 +02:00
+ + innerIndentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2010-01-14 21:41:50 +01:00
{
2010-04-06 22:17:23 +02:00
if ( innerIndentlevel = = 0 )
2010-01-14 21:41:50 +01:00
break ;
2010-04-06 22:17:23 +02:00
- - innerIndentlevel ;
2010-01-14 21:41:50 +01:00
}
2010-04-06 22:17:23 +02:00
while ( innerIndentlevel = = 0 & & Token : : Match ( tok3 , " [{};] if|ifv|else { continue ; } " ) )
2010-01-14 21:41:50 +01:00
{
Token : : eraseTokens ( tok3 , tok3 - > tokAt ( 6 ) ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok3 - > next ( ) , " else " ) )
2010-01-14 21:41:50 +01:00
tok3 - > deleteNext ( ) ;
}
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " while1 { if { dealloc ; return ; } } " ) )
2010-01-14 21:41:50 +01:00
{
tok2 - > str ( " ; " ) ;
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
Token : : eraseTokens ( tok2 - > tokAt ( 4 ) , tok2 - > tokAt ( 7 ) ) ;
}
}
}
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 ? tok2 - > next ( ) : NULL )
2009-01-15 21:34:39 +01:00
{
// Delete extra ";"
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " [;{}] ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace "{ }" with ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " { } " ) )
2009-01-15 21:34:39 +01:00
{
2010-01-10 20:03:46 +01:00
tok2 - > eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
tok2 - > insertToken ( " ; " ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete braces around a single instruction..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " { %var% ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-06-14 08:20:51 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 2 ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " { %var% %var% ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-06-14 08:12:04 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-23 22:42:07 +02:00
// reduce "; callfunc ; %var%"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " ; callfunc ; %type% " ) )
2009-09-23 22:42:07 +02:00
{
tok2 - > deleteNext ( ) ;
done = false ;
}
// Reduce "if if|callfunc" => "if"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " if if|callfunc " ) )
2009-06-16 19:05:05 +02:00
{
2009-09-23 22:42:07 +02:00
tok2 - > deleteNext ( ) ;
2009-06-16 19:05:05 +02:00
done = false ;
}
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
else if ( tok2 - > next ( ) & & tok2 - > next ( ) - > str ( ) = = " if " )
2009-01-15 21:34:39 +01:00
{
// Delete empty if that is not followed by an else
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-26 07:19:22 +02:00
// Reduce "if X ; else X ;" => "X ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if %var% ; else % var % ; " ) &&
std : : string ( tok2 - > strAt ( 2 ) ) = = std : : string ( tok2 - > strAt ( 5 ) ) )
2009-09-26 07:19:22 +02:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 5 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Two "if alloc ;" after one another.. perhaps only one of them can be executed each time
2010-04-10 14:05:33 +02:00
else if ( ! _settings - > inconclusive & & Token : : Match ( tok2 , " [;{}] if alloc ; if alloc ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " ; if ; else assign|use ; assign|use " ) | |
Token : : Match ( tok2 , " ; if assign|use ; else ; assign|use " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if return ; alloc ;" => "alloc ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if return ; alloc|return ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if alloc ; else return ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ; // Remove "if"
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 5 ) ) ; // Remove "; else return"
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if ; else %var% ;" => "if %var% ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if ; else % var % ; " ))
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-08-29 16:27:16 +02:00
// Reduce "if ; else" => "if"
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok2 - > next ( ) , " if ; else " ))
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-01-12 19:12:08 +01:00
// Reduce "if return ; else|if return|continue ;" => "if return ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if return ; else | if return | continue | break ; " ))
2009-01-15 21:34:39 +01:00
{
2010-01-12 19:12:08 +01:00
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 6 ) ) ;
done = false ;
}
// Reduce "if continue|break ; else|if return ;" => "if return ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if continue|break ; if | else return ; " ))
2010-01-12 19:12:08 +01:00
{
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-01 20:02:28 +02:00
// Delete "if { dealloc|assign|use ; return ; }"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if { dealloc|assign|use ; return ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 8 ) ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " else " ) )
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-02-08 19:27:09 +01:00
// Remove "if { dealloc ; callfunc ; } !!else"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if { dealloc | assign ; callfunc ; } ! ! else " ))
2009-02-08 19:27:09 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 8 ) ) ;
2009-02-08 19:27:09 +01:00
done = false ;
}
2009-01-15 21:34:39 +01:00
// Reducing if..
2010-04-10 14:05:33 +02:00
else if ( _settings - > inconclusive )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] if { assign|dealloc|use ; return ; } !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 8 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
}
continue ;
}
2010-01-24 21:48:39 +01:00
// Reduce "alloc while(!var) alloc ;" => "alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc ; while(!var) alloc ; " ) )
2010-01-19 19:08:03 +01:00
{
2010-01-24 21:48:39 +01:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2010-01-19 19:08:03 +01:00
done = false ;
2010-03-13 17:11:48 +01:00
}
// Reduce "ifv return;" => "if return use;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " ifv return ; " ) )
2010-03-13 17:11:48 +01:00
{
tok2 - > str ( " if " ) ;
tok2 - > next ( ) - > insertToken ( " use " ) ;
done = false ;
2010-01-19 19:08:03 +01:00
}
2009-01-15 21:34:39 +01:00
// Reduce "if(var) dealloc ;" and "if(var) use ;" that is not followed by an else..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] if(var) assign|dealloc|use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "; if(!var) alloc ; !!else" => "; dealloc ; alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; if(!var) alloc ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
// Remove the "if(!var)"
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
// Insert "dealloc ;" before the "alloc ;"
tok2 - > insertToken ( " ; " ) ;
tok2 - > insertToken ( " dealloc " ) ;
done = false ;
}
2009-08-29 16:03:23 +02:00
// Reduce "; if(!var) exit ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; if(!var) exit ; " ) )
2009-08-29 16:03:23 +02:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Remove "catch ;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " catch ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-08-29 16:27:16 +02:00
// Reduce "if* ;"..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var)|if(!var)|ifv ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-08-29 16:27:16 +02:00
// Followed by else..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > tokAt ( 3 ) , " else " ) )
2009-08-29 16:27:16 +02:00
{
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " if(var) " )
2009-08-29 16:27:16 +02:00
tok2 - > str ( " if(!var) " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " if(!var) " )
2009-08-29 16:27:16 +02:00
tok2 - > str ( " if(var) " ) ;
// remove the "; else"
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
}
else
{
// remove the "if* ;"
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
}
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "else ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " else ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-27 21:49:07 +02:00
// Reduce "while1 ;" => "use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 ; " ) )
2009-09-27 21:49:07 +02:00
{
tok2 - > str ( " use " ) ;
done = false ;
}
2010-01-14 21:41:50 +01:00
// Reduce "while1 if break ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 if break ; " ) )
2010-01-14 21:41:50 +01:00
{
tok2 - > str ( " ; " ) ;
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete if block: "alloc; if return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc ; if return use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-22 18:09:29 +02:00
// Reduce "alloc|dealloc|use|callfunc ; exit ;" => "; exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc|dealloc|use|callfunc ; exit ; " ) )
2009-07-23 16:30:30 +02:00
{
2010-02-20 10:17:45 +01:00
tok2 - > deleteNext ( ) ;
2009-07-23 16:30:30 +02:00
done = false ;
}
2009-09-22 18:09:29 +02:00
// Reduce "if loop ; exit ;" => "; exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " if loop ; exit ; " ) )
2009-09-22 18:09:29 +02:00
{
tok2 - > deleteThis ( ) ;
tok2 - > deleteThis ( ) ;
done = false ;
}
2009-07-23 16:30:30 +02:00
// Reduce "alloc|dealloc|use ; if(var) exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc|dealloc|use ; if(var) exit ; " ) )
2009-07-23 16:30:30 +02:00
{
tok2 - > deleteThis ( ) ;
done = false ;
}
// Remove "if exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " if exit ; " ) )
2009-07-23 16:30:30 +02:00
{
tok2 - > deleteThis ( ) ;
tok2 - > deleteThis ( ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Remove the "if break|continue ;" that follows "dealloc ; alloc ;"
2010-04-10 14:05:33 +02:00
if ( ! _settings - > inconclusive & & Token : : Match ( tok2 , " dealloc ; alloc ; if break|continue ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-14 08:12:04 +02:00
tok2 = tok2 - > tokAt ( 3 ) ;
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-01-24 21:48:39 +01:00
// Reduce "do { dealloc ; alloc ; } while(var) ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " do { dealloc ; alloc ; } while(var) ; " ) )
2010-01-24 21:48:39 +01:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 9 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Reduce "do { alloc ; } " => "alloc ;"
2009-07-14 08:17:12 +02:00
/** @todo If the loop "do { alloc ; }" can be executed twice, reduce it to "loop alloc ;" */
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " do { alloc ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-06-14 08:20:51 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 2 ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-26 07:19:22 +02:00
// Reduce "loop break ; => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop break|continue ; " ) )
2009-09-26 07:19:22 +02:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2010-01-10 15:40:50 +01:00
// Reduce "loop|do ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " loop|do ; " ) )
2010-01-10 14:00:32 +01:00
{
2010-01-10 15:40:50 +01:00
tok2 - > deleteThis ( ) ;
2010-01-10 14:00:32 +01:00
done = false ;
}
2009-01-15 21:34:39 +01:00
// Reduce "loop if break ; => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop if break|continue ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "loop { assign|dealloc|use ; alloc ; if break ; }" to "assign|dealloc|use ; alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop { assign|dealloc|use ; alloc ; if break|continue ; } " ) )
2009-01-15 21:34:39 +01:00
{
// erase "loop {"
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
// erase "if break|continue ; }"
2009-06-14 08:09:02 +02:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace "loop { X ; break ; }" with "X ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop { %var% ; break ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-06-14 08:20:51 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 2 ) , tok2 - > tokAt ( 6 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-15 22:26:38 +02:00
// Replace "do ; loop ;" with ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " %any% ; loop ; " ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > next ( ) - > str ( ) = = " do " )
2009-09-15 22:26:38 +02:00
tok2 - > deleteNext ( ) ;
else
tok2 = tok2 - > next ( ) ;
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-15 22:26:38 +02:00
// Replace "do ; loop !var ;" with ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " %any% ; loop !var ; " ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > next ( ) - > str ( ) = = " do " )
2009-09-15 22:26:38 +02:00
tok2 - > deleteNext ( ) ;
else
tok2 = tok2 - > next ( ) ;
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-01-17 08:55:40 +01:00
// Replace "loop if return ;" with "if return ;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " loop if return " ) )
2009-01-17 08:55:40 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-17 08:55:40 +01:00
done = false ;
2009-01-15 21:34:39 +01:00
}
// Delete if block in "alloc ; if(!var) return ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc ; if(!var) return ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete if block: "alloc; if return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc ; if return use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "[;{}] return ; %var%" => "[;{}] return ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] return ; %var% " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-14 08:20:51 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 2 ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "[;{}] return use ; %var%" => "[;{}] return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] return use ; %var% " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-14 08:12:04 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if(var) return use ;" => "return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var) return use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if(var) assign|dealloc|use ;" => "assign|dealloc|use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var) assign|dealloc|use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-02-07 10:44:57 +01:00
// malloc - realloc => alloc ; dealloc ; alloc ;
// Reduce "[;{}] alloc ; dealloc ; alloc ;" => "[;{}] alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc ; dealloc ; alloc ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 6 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete second use in "use ; use ;"
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " [;{}] use ; use ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete first part in "use ; dealloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] use ; dealloc ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete first part in "use ; return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] use ; return use ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-06-21 21:03:58 +02:00
// Delete "callfunc ;" that is followed by "use|if|callfunc"
// If the function doesn't throw exception or exit the application, then the "callfunc" is not needed
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " callfunc ; use|if|callfunc " ) )
2009-06-21 21:03:58 +02:00
{
tok2 - > deleteThis ( ) ;
done = false ;
}
2009-06-21 14:12:59 +02:00
2009-01-15 21:34:39 +01:00
// Delete second case in "case ; case ;"
2010-04-02 07:30:58 +02:00
while ( Token : : simpleMatch ( tok2 , " case ; case ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace switch with if (if not complicated)
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " switch { " ) )
2009-01-15 21:34:39 +01:00
{
// Right now, I just handle if there are a few case and perhaps a default.
bool valid = false ;
bool incase = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * _tok = tok2 - > tokAt ( 2 ) ; _tok ; _tok = _tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( _tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( _tok - > str ( ) = = " } " )
2009-01-15 21:34:39 +01:00
{
valid = true ;
break ;
}
2010-04-02 07:30:58 +02:00
else if ( _tok - > str ( ) = = " switch " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( _tok - > str ( ) = = " loop " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( incase & & _tok - > str ( ) = = " case " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( _tok , " return !!; " ) )
2010-01-10 10:37:54 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( _tok , " if return|break use| ; " ) )
2010-01-10 15:40:50 +01:00
_tok = _tok - > tokAt ( 2 ) ;
2009-07-27 11:24:24 +02:00
incase | = ( _tok - > str ( ) = = " case " ) ;
2010-01-10 10:37:54 +01:00
incase & = ( _tok - > str ( ) ! = " break " & & _tok - > str ( ) ! = " return " ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ! incase & & valid )
2009-01-15 21:34:39 +01:00
{
done = false ;
tok2 - > str ( " ; " ) ;
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 - > next ( ) ;
bool first = true ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " case|default " ) )
2009-01-15 21:34:39 +01:00
{
2010-01-10 10:37:54 +01:00
const bool def ( tok2 - > str ( ) = = " default " ) ;
2009-01-15 21:34:39 +01:00
tok2 - > str ( first ? " if " : " } " ) ;
2010-04-02 07:30:58 +02:00
if ( first )
2009-01-15 21:34:39 +01:00
{
first = false ;
tok2 - > insertToken ( " { " ) ;
}
else
{
// Insert "else [if] {
tok2 - > insertToken ( " { " ) ;
2010-04-02 07:30:58 +02:00
if ( ! def )
2009-01-15 21:34:39 +01:00
tok2 - > insertToken ( " if " ) ;
tok2 - > insertToken ( " else " ) ;
tok2 = tok2 - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
while ( tok2 )
2010-01-10 15:40:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " } " )
2010-01-10 15:40:50 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " break|return ; " ) )
2010-01-10 15:40:50 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " if return|break use| ; " ) )
2010-01-10 15:40:50 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
else
tok2 = tok2 - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " break ; " ) )
2009-01-15 21:34:39 +01:00
{
tok2 - > str ( " ; " ) ;
2009-06-14 08:20:51 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( tok2 & & tok2 - > str ( ) = = " return " )
2010-01-10 10:37:54 +01:00
{
tok2 = tok2 - > tokAt ( 2 ) ;
}
2009-01-15 21:34:39 +01:00
}
}
}
}
2009-07-23 16:30:30 +02:00
2009-09-23 22:42:07 +02:00
// If "--all" is given, remove all "callfunc"..
2010-04-10 14:05:33 +02:00
if ( done & & _settings - > inconclusive )
2009-09-23 22:42:07 +02:00
{
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-09-23 22:42:07 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " callfunc " )
2009-09-23 22:42:07 +02:00
{
tok2 - > deleteThis ( ) ;
done = false ;
}
}
}
}
2009-01-15 21:34:39 +01:00
}
2010-05-16 19:55:16 +02:00
const Token * CheckMemoryLeakInFunction : : findleak ( const Token * tokens )
2009-08-23 15:48:25 +02:00
{
2009-10-08 22:30:33 +02:00
const Token * result ;
2009-08-23 15:48:25 +02:00
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " loop alloc ; " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
return result ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tokens , " alloc ; if|if(var)|ifv break|continue|return ; " ) )
2009-11-15 10:30:00 +01:00
{
return tokens - > tokAt ( 3 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; if|if(var)|ifv return ; " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
return result - > tokAt ( 3 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; alloc|assign|return callfunc| ; " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
return result - > tokAt ( 2 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; if assign ; " ) ) ! = NULL )
2009-09-01 19:33:17 +02:00
{
return result - > tokAt ( 3 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; } " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
2010-04-02 07:30:58 +02:00
if ( result - > tokAt ( 3 ) = = NULL )
2009-08-23 15:48:25 +02:00
return result - > tokAt ( 2 ) ;
}
// No deallocation / usage => report leak at the last token
2010-04-02 07:30:58 +02:00
if ( ! Token : : findmatch ( tokens , " dealloc|use " ) )
2009-08-23 15:48:25 +02:00
{
const Token * last = tokens ;
2010-04-02 07:30:58 +02:00
while ( last - > next ( ) )
2009-08-23 15:48:25 +02:00
last = last - > next ( ) ;
2009-12-03 19:19:20 +01:00
// check if we call exit before the end of the funcion
Token * tok2 = last - > previous ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 )
2009-12-03 19:19:20 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " ; " ) )
2009-12-03 21:48:52 +01:00
{
2009-12-03 19:19:20 +01:00
const Token * tok3 = tok2 - > previous ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok3 & & Token : : simpleMatch ( tok3 , " exit " ) )
2009-12-03 19:19:20 +01:00
{
return NULL ;
}
}
}
2009-08-23 15:48:25 +02:00
return last ;
}
return NULL ;
}
2009-06-08 20:20:43 +02:00
2009-01-15 21:34:39 +01:00
// Check for memory leaks for a function variable.
2009-09-10 21:22:57 +02:00
void CheckMemoryLeakInFunction : : checkScope ( const Token * Tok1 , const std : : string & varname , unsigned int varid , bool classmember , unsigned int sz )
2009-01-15 21:34:39 +01:00
{
std : : list < const Token * > callstack ;
AllocType alloctype = No ;
AllocType dealloctype = No ;
const Token * result ;
2010-05-16 19:55:16 +02:00
Token * tok = getcode ( Tok1 , callstack , varid , alloctype , dealloctype , classmember , sz ) ;
2009-08-02 22:30:43 +02:00
//tok->printOut((std::string("Checkmemoryleak: getcode result for: ") + varname).c_str());
2009-01-15 21:34:39 +01:00
// Simplify the code and check if freed memory is used..
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " [;{}] ; " ) )
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tok , " [;{}] dealloc ; use_ ; " ) ) ! = NULL )
2009-01-15 21:34:39 +01:00
{
2009-05-30 20:30:44 +02:00
deallocuseError ( result - > tokAt ( 3 ) , varname ) ;
2009-01-15 21:34:39 +01:00
}
2009-01-24 19:55:56 +01:00
// Replace "&use" with "use". Replace "use_" with ";"
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " &use " )
2009-01-15 21:34:39 +01:00
tok2 - > str ( " use " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " use_ " )
2009-01-15 21:34:39 +01:00
tok2 - > str ( " ; " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ::use " ) // Some kind of member function usage. Not analyzed very well.
2009-01-26 19:15:44 +01:00
tok2 - > str ( " use " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " recursive " )
2009-01-16 17:29:41 +01:00
tok2 - > str ( " use " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " dealloc_ " )
2009-01-15 21:34:39 +01:00
tok2 - > str ( " dealloc " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " realloc " )
2009-01-15 21:34:39 +01:00
{
tok2 - > str ( " dealloc " ) ;
tok2 - > insertToken ( " alloc " ) ;
tok2 - > insertToken ( " ; " ) ;
}
}
2009-10-08 20:49:27 +02:00
// If the variable is not allocated at all => no memory leak
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , " alloc " ) = = 0 )
2009-10-08 20:49:27 +02:00
{
Tokenizer : : deleteTokens ( tok ) ;
return ;
}
2010-05-16 19:55:16 +02:00
simplifycode ( tok ) ;
2009-08-02 21:23:47 +02:00
2010-04-02 07:30:58 +02:00
if ( _settings - > _debug & & _settings - > _verbose )
2009-08-02 21:23:47 +02:00
{
2009-08-19 19:42:07 +02:00
tok - > printOut ( ( " Checkmemoryleak: simplifycode result for: " + varname ) . c_str ( ) ) ;
2009-08-02 21:23:47 +02:00
}
2009-01-15 21:34:39 +01:00
// If the variable is not allocated at all => no memory leak
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , " alloc " ) = = 0 )
2009-01-15 21:34:39 +01:00
{
Tokenizer : : deleteTokens ( tok ) ;
return ;
}
2009-07-14 08:17:12 +02:00
/** @todo handle "goto" */
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , " goto " ) )
2009-01-15 21:34:39 +01:00
{
Tokenizer : : deleteTokens ( tok ) ;
return ;
}
2010-05-16 19:55:16 +02:00
if ( ( result = findleak ( tok ) ) ! = NULL )
2009-01-15 21:34:39 +01:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( result , varname , alloctype ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( ( result = Token : : findmatch ( tok , " dealloc ; dealloc ; " ) ) ! = NULL )
2009-01-15 21:34:39 +01:00
{
2009-03-21 17:58:13 +01:00
deallocDeallocError ( result - > tokAt ( 2 ) , varname ) ;
2009-01-15 21:34:39 +01:00
}
// detect cases that "simplifycode" don't handle well..
2010-04-02 07:30:58 +02:00
else if ( _settings - > _debug )
2009-01-15 21:34:39 +01:00
{
Token * first = tok ;
2010-04-02 07:30:58 +02:00
while ( first & & first - > str ( ) = = " ; " )
2009-01-15 21:34:39 +01:00
first = first - > next ( ) ;
bool noerr = false ;
2009-05-21 17:55:52 +02:00
noerr | = Token : : simpleMatch ( first , " alloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; dealloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; return use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; use ; return ; } " ) ;
noerr | = Token : : simpleMatch ( first , " if alloc ; dealloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " if alloc ; return use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " if alloc ; use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; ifv return ; dealloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; if return ; dealloc; } " ) ;
2009-01-15 21:34:39 +01:00
// Unhandled case..
2010-04-02 07:30:58 +02:00
if ( ! noerr )
2009-01-15 21:34:39 +01:00
{
std : : cout < < " Token listing.. \n " ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
std : : cout < < " " < < tok2 - > str ( ) ;
std : : cout < < " \n " ;
}
}
Tokenizer : : deleteTokens ( tok ) ;
}
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
2010-05-18 07:46:48 +02:00
//---------------------------------------------------------------------------
// Check for memory leaks due to improper realloc() usage.
// Below, "a" may be set to null without being freed if realloc() cannot
// allocate the requested memory:
// a = malloc(10); a = realloc(a, 100);
//---------------------------------------------------------------------------
void CheckMemoryLeakInFunction : : checkReallocUsage ( )
{
const Token * tok = _tokenizer - > tokens ( ) ;
for ( ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " %var% = realloc|g_try_realloc ( %var% , " ) )
{
if ( tok - > varId ( ) = = tok - > tokAt ( 4 ) - > varId ( ) )
{
memleakUponReallocFailureError ( tok , tok - > str ( ) ) ;
}
}
}
}
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
2009-01-15 21:34:39 +01:00
//---------------------------------------------------------------------------
// Checks for memory leaks inside function..
//---------------------------------------------------------------------------
2010-04-24 22:24:03 +02:00
void CheckMemoryLeakInFunction : : parseFunctionScope ( const Token * tok , const Token * tok1 , const bool classmember )
2009-01-15 21:34:39 +01:00
{
2009-12-30 21:29:54 +01:00
// Check locking/unlocking of global resources..
checkScope ( tok - > next ( ) , " " , 0 , classmember , 1 ) ;
2009-11-14 09:06:28 +01:00
2010-04-24 22:24:03 +02:00
// Locate parameters and check their usage..
for ( const Token * tok2 = tok1 ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 = = tok )
break ;
if ( tok2 - > str ( ) = = " ) " )
break ;
if ( Token : : Match ( tok2 , " [(,] %type% * %var% [,)] " ) & & tok2 - > next ( ) - > isStandardType ( ) )
{
const std : : string varname ( tok2 - > strAt ( 3 ) ) ;
const unsigned int varid = tok2 - > tokAt ( 3 ) - > varId ( ) ;
const unsigned int sz = _tokenizer - > sizeOfType ( tok - > next ( ) ) ;
checkScope ( tok - > next ( ) , varname , varid , classmember , sz ) ;
}
}
2009-12-30 21:29:54 +01:00
// Locate variable declarations and check their usage..
unsigned int indentlevel = 0 ;
do
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-12-30 21:29:54 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 1 )
2009-12-30 21:29:54 +01:00
break ;
2009-01-15 21:34:39 +01:00
- - indentlevel ;
2009-12-30 21:29:54 +01:00
}
2009-01-15 21:34:39 +01:00
2009-07-31 23:42:21 +02:00
// Skip these weird blocks... "( { ... } )"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " ( { " ) )
2009-07-31 23:42:21 +02:00
{
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-07-31 23:42:21 +02:00
break ;
continue ;
}
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " [{};] %type% " ) )
2009-12-30 21:29:54 +01:00
continue ;
2009-01-15 21:34:39 +01:00
2009-12-30 21:29:54 +01:00
// Don't check static/extern variables
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > next ( ) , " static|extern " ) )
2009-12-30 21:29:54 +01:00
continue ;
2009-05-21 21:51:19 +02:00
2009-12-30 21:29:54 +01:00
// return/else is not part of a variable declaration..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > next ( ) , " return|else " ) )
2009-12-30 21:29:54 +01:00
continue ;
2009-03-10 20:44:24 +01:00
2009-12-30 21:29:54 +01:00
unsigned int sz = _tokenizer - > sizeOfType ( tok - > next ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( sz < 1 )
2009-12-30 21:29:54 +01:00
sz = 1 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [{};] %type% * const| %var% [;=] " ) )
2009-12-30 21:29:54 +01:00
{
const Token * vartok = tok - > tokAt ( tok - > tokAt ( 3 ) - > str ( ) ! = " const " ? 3 : 4 ) ;
checkScope ( tok - > next ( ) , vartok - > str ( ) , vartok - > varId ( ) , classmember , sz ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [{};] %type% %type% * const| %var% [;=] " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-30 21:29:54 +01:00
const Token * vartok = tok - > tokAt ( tok - > tokAt ( 4 ) - > str ( ) ! = " const " ? 4 : 5 ) ;
checkScope ( tok - > next ( ) , vartok - > str ( ) , vartok - > varId ( ) , classmember , sz ) ;
}
2009-02-07 11:54:39 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [{};] int %var% [;=] " ) )
2009-12-30 21:29:54 +01:00
{
const Token * vartok = tok - > tokAt ( 2 ) ;
checkScope ( tok - > next ( ) , vartok - > str ( ) , vartok - > varId ( ) , classmember , sz ) ;
}
}
2010-04-02 07:30:58 +02:00
while ( 0 ! = ( tok = tok - > next ( ) ) ) ;
2009-12-30 21:29:54 +01:00
}
2009-07-06 12:20:13 +02:00
2009-12-30 21:29:54 +01:00
void CheckMemoryLeakInFunction : : check ( )
{
// Parse the tokens and fill the "noreturn"
parse_noreturn ( ) ;
2009-07-06 12:20:13 +02:00
2009-12-30 21:29:54 +01:00
bool classmember = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-12-30 21:29:54 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2010-03-20 07:50:52 +01:00
{
tok = tok - > link ( ) ;
}
2009-12-30 21:29:54 +01:00
// Found a function scope
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " ) const| { " ) )
2009-12-30 21:29:54 +01:00
{
2010-04-24 22:24:03 +02:00
const Token * const tok1 = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
while ( tok - > str ( ) ! = " { " )
2009-12-30 21:29:54 +01:00
tok = tok - > next ( ) ;
2010-04-24 22:24:03 +02:00
parseFunctionScope ( tok , tok1 , classmember ) ;
2009-12-30 21:29:54 +01:00
tok = tok - > link ( ) ;
continue ;
}
2009-08-29 15:20:37 +02:00
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " :: " )
2009-12-30 21:29:54 +01:00
classmember = true ;
2009-06-21 17:01:43 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [;}] " ) )
2009-12-30 21:29:54 +01:00
classmember = false ;
2009-01-15 21:34:39 +01:00
}
}
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
2009-01-15 21:34:39 +01:00
//---------------------------------------------------------------------------
// Checks for memory leaks in classes..
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
void CheckMemoryLeakInClass : : check ( )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-01-27 21:02:13 +01:00
tok = tok - > link ( ) ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " class %var% [{:] " ) )
2009-01-15 21:34:39 +01:00
{
2010-01-27 21:02:13 +01:00
std : : vector < std : : string > classname ;
2009-01-15 21:34:39 +01:00
classname . push_back ( tok - > strAt ( 1 ) ) ;
2009-06-08 20:20:43 +02:00
parseClass ( tok , classname ) ;
2009-01-15 21:34:39 +01:00
}
}
}
2010-01-27 21:02:13 +01:00
void CheckMemoryLeakInClass : : parseClass ( const Token * tok1 , std : : vector < std : : string > & classname )
2009-01-15 21:34:39 +01:00
{
// Go into class.
2010-04-02 07:30:58 +02:00
while ( tok1 & & tok1 - > str ( ) ! = " { " )
2009-01-15 21:34:39 +01:00
tok1 = tok1 - > next ( ) ;
2010-01-27 22:05:04 +01:00
tok1 = tok1 ? tok1 - > next ( ) : 0 ;
2009-01-15 21:34:39 +01:00
2010-05-15 19:40:32 +02:00
// are we parsing the private scope of the class?
bool privateScope = true ;
2010-01-27 22:05:04 +01:00
unsigned int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2009-01-15 21:34:39 +01:00
return ;
2010-01-27 22:05:04 +01:00
- - indentlevel ;
2009-01-15 21:34:39 +01:00
}
2010-05-15 19:40:32 +02:00
else if ( tok - > isName ( ) & & tok - > str ( ) . find ( " : " ) ! = std : : string : : npos )
privateScope = bool ( tok - > str ( ) = = " private: " ) ;
2009-01-15 21:34:39 +01:00
// Only parse this particular class.. not subclasses
2010-04-02 07:30:58 +02:00
if ( indentlevel > 0 )
2009-01-15 21:34:39 +01:00
continue ;
2009-10-06 18:25:00 +02:00
// skip static variables..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " static %type% * %var% ; " ) )
2009-10-06 18:25:00 +02:00
{
tok = tok - > tokAt ( 4 ) ;
}
2009-01-15 21:34:39 +01:00
// Declaring subclass.. recursive checking
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " class %var% [{:] " ) )
2009-01-15 21:34:39 +01:00
{
classname . push_back ( tok - > strAt ( 1 ) ) ;
2009-06-08 20:20:43 +02:00
parseClass ( tok , classname ) ;
2009-01-15 21:34:39 +01:00
classname . pop_back ( ) ;
}
// Declaring member variable.. check allocations and deallocations
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > previous ( ) , " ;|{|}|private:|protected:|public: %type% * %var% ; " ) )
2009-01-15 21:34:39 +01:00
{
2010-05-15 19:40:32 +02:00
// allocation but no deallocation of private variables in public function..
if ( privateScope & & tok - > isStandardType ( ) )
checkPublicFunctions ( tok1 , tok - > tokAt ( 2 ) - > varId ( ) ) ;
2010-05-16 07:15:31 +02:00
if ( ! isclass ( _tokenizer , tok ) )
2010-01-27 22:05:04 +01:00
variable ( classname . back ( ) , tok - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
}
}
}
2010-01-27 21:02:13 +01:00
void CheckMemoryLeakInClass : : variable ( const std : : string & classname , const Token * tokVarname )
2009-01-15 21:34:39 +01:00
{
2010-04-10 14:05:33 +02:00
if ( ! _settings - > inconclusive )
2009-09-12 21:13:47 +02:00
return ;
2010-01-27 21:02:13 +01:00
const std : : string varname = tokVarname - > strAt ( 0 ) ;
2009-03-01 21:34:04 +01:00
2009-01-15 21:34:39 +01:00
// Check if member variable has been allocated and deallocated..
2009-06-08 20:20:43 +02:00
CheckMemoryLeak : : AllocType Alloc = CheckMemoryLeak : : No ;
CheckMemoryLeak : : AllocType Dealloc = CheckMemoryLeak : : No ;
2009-01-15 21:34:39 +01:00
2009-10-23 20:04:47 +02:00
bool allocInConstructor = false ;
bool deallocInDestructor = false ;
2009-01-15 21:34:39 +01:00
// Loop through all tokens. Inspect member functions
2009-03-14 18:21:37 +01:00
int indent_ = 0 ;
2010-01-29 22:22:18 +01:00
const Token * functionToken = _tokenizer - > findClassFunction ( _tokenizer - > tokens ( ) , classname . c_str ( ) , " ~| %var% " , indent_ ) ;
2010-04-02 07:30:58 +02:00
while ( functionToken )
2009-01-15 21:34:39 +01:00
{
2010-03-19 16:57:23 +01:00
const bool constructor ( Token : : Match ( functionToken , ( classname + " ( " ) . c_str ( ) ) | | Token : : Match ( functionToken , ( classname + " :: " + classname + " ( " ) . c_str ( ) ) ) ;
const bool destructor ( functionToken - > str ( ) = = " ~ " | | functionToken - > tokAt ( 2 ) - > str ( ) = = " ~ " ) ;
2009-10-22 21:51:58 +02:00
2010-01-27 21:02:13 +01:00
unsigned int indent = 0 ;
2009-03-14 20:19:36 +01:00
bool initlist = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = functionToken ; tok ; tok = tok - > next ( ) )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-03-14 18:21:37 +01:00
+ + indent ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent < = 1 )
2009-03-14 18:21:37 +01:00
break ;
2010-01-27 21:02:13 +01:00
- - indent ;
2009-03-14 18:21:37 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( indent = = 0 & & Token : : simpleMatch ( tok , " ) : " ) )
2009-03-14 20:19:36 +01:00
initlist = true ;
2010-04-02 07:30:58 +02:00
else if ( initlist | | indent > 0 )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent = = 0 )
2009-03-14 20:19:36 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , ( " :|, " + varname + " ( " ) . c_str ( ) ) )
2009-03-14 20:19:36 +01:00
continue ;
}
2009-03-14 18:21:37 +01:00
// Allocate..
2010-04-02 07:30:58 +02:00
if ( indent = = 0 | | Token : : Match ( tok , ( varname + " = " ) . c_str ( ) ) )
2009-03-14 18:21:37 +01:00
{
2009-08-19 19:42:07 +02:00
AllocType alloc = getAllocationType ( tok - > tokAt ( ( indent > 0 ) ? 2 : 3 ) , 0 ) ;
2010-04-02 07:30:58 +02:00
if ( alloc ! = CheckMemoryLeak : : No )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( constructor )
2009-10-23 20:04:47 +02:00
allocInConstructor = true ;
2010-04-02 07:30:58 +02:00
if ( Alloc ! = No & & Alloc ! = alloc )
2009-06-08 20:20:43 +02:00
alloc = CheckMemoryLeak : : Many ;
2009-01-15 21:34:39 +01:00
2009-03-14 18:21:37 +01:00
std : : list < const Token * > callstack ;
2010-04-02 07:30:58 +02:00
if ( alloc ! = CheckMemoryLeak : : Many & & Dealloc ! = CheckMemoryLeak : : No & & Dealloc ! = CheckMemoryLeak : : Many & & Dealloc ! = alloc )
2009-03-14 18:21:37 +01:00
{
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , classname + " :: " + varname ) ;
2009-03-14 18:21:37 +01:00
callstack . pop_back ( ) ;
}
2009-01-15 21:34:39 +01:00
2009-03-14 18:21:37 +01:00
Alloc = alloc ;
}
}
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( indent = = 0 )
2009-03-14 20:19:36 +01:00
continue ;
2009-03-14 18:21:37 +01:00
// Deallocate..
const char * varnames [ 3 ] = { " var " , 0 , 0 } ;
2010-01-27 21:02:13 +01:00
varnames [ 0 ] = varname . c_str ( ) ;
2009-07-05 22:16:43 +02:00
AllocType dealloc = getDeallocationType ( tok , varnames ) ;
2010-04-02 07:30:58 +02:00
if ( dealloc = = No )
2009-01-15 21:34:39 +01:00
{
2009-03-14 18:21:37 +01:00
varnames [ 0 ] = " this " ;
2010-01-27 21:02:13 +01:00
varnames [ 1 ] = varname . c_str ( ) ;
2009-07-05 22:16:43 +02:00
dealloc = getDeallocationType ( tok , varnames ) ;
2009-03-14 18:21:37 +01:00
}
2010-04-02 07:30:58 +02:00
if ( dealloc ! = CheckMemoryLeak : : No )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( destructor )
2009-10-23 20:04:47 +02:00
deallocInDestructor = true ;
2010-01-27 21:02:13 +01:00
// several types of allocation/deallocation?
2010-04-02 07:30:58 +02:00
if ( Dealloc ! = CheckMemoryLeak : : No & & Dealloc ! = dealloc )
2009-06-08 20:20:43 +02:00
dealloc = CheckMemoryLeak : : Many ;
2009-02-06 07:11:47 +01:00
2009-01-15 21:34:39 +01:00
std : : list < const Token * > callstack ;
2010-04-02 07:30:58 +02:00
if ( dealloc ! = CheckMemoryLeak : : Many & & Alloc ! = CheckMemoryLeak : : No & & Alloc ! = Many & & Alloc ! = dealloc )
2009-02-01 16:47:36 +01:00
{
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , classname + " :: " + varname ) ;
2009-02-01 16:47:36 +01:00
callstack . pop_back ( ) ;
}
2009-02-06 07:11:47 +01:00
2009-03-14 18:21:37 +01:00
Dealloc = dealloc ;
2009-01-15 21:34:39 +01:00
}
2009-10-24 15:07:14 +02:00
// Function call in destructor .. possible deallocation
2010-04-02 07:30:58 +02:00
else if ( destructor & & Token : : Match ( tok - > previous ( ) , " [ { } ; ] % var % ( " ))
2009-10-24 15:07:14 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! std : : bsearch ( tok - > str ( ) . c_str ( ) , call_func_white_list ,
sizeof ( call_func_white_list ) / sizeof ( call_func_white_list [ 0 ] ) ,
sizeof ( call_func_white_list [ 0 ] ) , call_func_white_list_compare ) )
2009-10-24 15:07:14 +02:00
{
return ;
}
}
2009-01-23 20:24:52 +01:00
}
2009-01-15 21:34:39 +01:00
}
2009-03-14 18:21:37 +01:00
2010-01-29 22:22:18 +01:00
functionToken = _tokenizer - > Tokenizer : : findClassFunction ( functionToken - > next ( ) , classname . c_str ( ) , " ~| %var% " , indent_ ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( allocInConstructor & & ! deallocInDestructor )
2009-10-23 20:04:47 +02:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tokVarname , ( classname + " :: " + varname ) . c_str ( ) , Alloc ) ;
2009-10-23 20:04:47 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Alloc ! = CheckMemoryLeak : : No & & Dealloc = = CheckMemoryLeak : : No )
2009-01-15 21:34:39 +01:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tokVarname , ( classname + " :: " + varname ) . c_str ( ) , Alloc ) ;
2009-01-15 21:34:39 +01:00
}
}
2010-05-15 19:40:32 +02:00
void CheckMemoryLeakInClass : : checkPublicFunctions ( const Token * classtok , const unsigned int varid )
{
// Check that public functions deallocate the pointers that they allocate.
// There is no checking how these functions are used and therefore it
// isn't established if there is real leaks or not.
if ( ! _settings - > _checkCodingStyle )
return ;
2009-01-15 21:34:39 +01:00
2010-05-15 19:40:32 +02:00
// Parse public functions..
// If they allocate member variables, they should also deallocate
bool publicScope = false ;
for ( const Token * tok = classtok ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
tok = tok - > link ( ) ;
else if ( tok - > str ( ) = = " } " )
break ;
else if ( tok - > isName ( ) & & tok - > str ( ) . find ( " : " ) ! = std : : string : : npos )
publicScope = bool ( tok - > str ( ) = = " public: " ) ;
2009-01-15 21:34:39 +01:00
2010-05-15 19:40:32 +02:00
// scope of public function..
// TODO: parse into any function scope that is not a constructor
else if ( publicScope & & ( Token : : Match ( tok , " void %type% ( " ) | | Token : : simpleMatch ( tok , " operator = ( " ) ) )
{
tok = tok - > tokAt ( 2 ) - > link ( ) ;
if ( Token : : Match ( tok , " ) const| { " ) )
{
const Token * tok2 = tok ;
while ( tok2 - > str ( ) ! = " { " )
tok2 = tok2 - > next ( ) ;
if ( Token : : Match ( tok2 , " { %varid% = " , varid ) )
{
const CheckMemoryLeak : : AllocType alloc = getAllocationType ( tok2 - > tokAt ( 3 ) , varid ) ;
if ( alloc ! = CheckMemoryLeak : : No )
publicAllocationError ( tok2 , tok2 - > strAt ( 1 ) ) ;
}
}
}
}
}
2009-01-15 21:34:39 +01:00
2010-05-15 19:40:32 +02:00
void CheckMemoryLeakInClass : : publicAllocationError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " publicAllocationError " , " Possible leak in public function. The pointer ' " + varname + " ' is not deallocated before it is allocated. " ) ;
}
2009-01-15 21:34:39 +01:00
2009-07-19 16:51:31 +02:00
void CheckMemoryLeakStructMember : : check ( )
{
2009-07-22 08:30:51 +02:00
// This should be in the CheckMemoryLeak base class
std : : set < std : : string > ignoredFunctions ;
ignoredFunctions . insert ( " if " ) ;
ignoredFunctions . insert ( " for " ) ;
ignoredFunctions . insert ( " while " ) ;
ignoredFunctions . insert ( " malloc " ) ;
2009-09-28 22:58:06 +02:00
unsigned int indentlevel1 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-09-28 22:58:06 +02:00
+ + indentlevel1 ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-09-28 22:58:06 +02:00
- - indentlevel1 ;
2009-07-19 16:51:31 +02:00
// Locate struct variables..
2010-04-02 07:30:58 +02:00
if ( indentlevel1 > 0 & & Token : : Match ( tok , " struct|;|{|} %type% * %var% [=;] " ) )
2009-07-19 16:51:31 +02:00
{
2009-07-29 11:38:20 +02:00
const Token * const vartok = tok - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
if ( vartok - > varId ( ) = = 0 )
2009-07-19 16:51:31 +02:00
continue ;
// Check that struct is allocated..
{
const unsigned int varid ( vartok - > varId ( ) ) ;
bool alloc = false ;
unsigned int indentlevel2 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = vartok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-07-19 16:51:31 +02:00
+ + indentlevel2 ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel2 = = 0 )
2009-07-19 16:51:31 +02:00
break ;
- - indentlevel2 ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " = %varid% [;=] " , varid ) )
2009-07-19 16:51:31 +02:00
{
alloc = false ;
break ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %varid% = malloc|kmalloc ( " , varid ) )
2009-07-19 16:51:31 +02:00
{
alloc = true ;
}
}
2010-04-02 07:30:58 +02:00
if ( ! alloc )
2009-07-19 16:51:31 +02:00
continue ;
}
// Check struct..
unsigned int indentlevel2 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = vartok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-07-19 16:51:31 +02:00
+ + indentlevel2 ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel2 = = 0 )
2009-07-19 16:51:31 +02:00
break ;
- - indentlevel2 ;
}
2009-07-29 11:38:20 +02:00
// Unknown usage of struct
/** @todo Check how the struct is used. Only bail out if necessary */
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [(,] %varid% [,)] " , vartok - > varId ( ) ) )
2009-07-29 11:38:20 +02:00
break ;
2009-07-19 16:51:31 +02:00
// Struct member is allocated => check if it is also properly deallocated..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %varid% . %var% = malloc|strdup|kmalloc ( " , vartok - > varId ( ) ) )
2009-07-19 16:51:31 +02:00
{
const unsigned int structid ( vartok - > varId ( ) ) ;
const unsigned int structmemberid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
// This struct member is allocated.. check that it is deallocated
unsigned int indentlevel3 = indentlevel2 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > next ( ) )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2009-07-19 16:51:31 +02:00
+ + indentlevel3 ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2009-07-19 16:51:31 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel3 = = 0 )
2009-07-19 16:51:31 +02:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tok3 , ( vartok - > str ( ) + " . " + tok2 - > strAt ( 2 ) ) . c_str ( ) , Malloc ) ;
2009-07-19 16:51:31 +02:00
break ;
}
- - indentlevel3 ;
}
// Deallocating the struct member..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " free|kfree ( %var% . %varid% ) " , structmemberid ) )
2009-07-20 14:39:24 +02:00
{
// If the deallocation happens at the base level, don't check this member anymore
2010-04-02 07:30:58 +02:00
if ( indentlevel3 = = 0 )
2009-07-20 14:39:24 +02:00
break ;
// deallocating and then returning from function in a conditional block =>
// skip ahead out of the block
bool ret = false ;
2010-04-02 07:30:58 +02:00
while ( tok3 )
2009-07-20 14:39:24 +02:00
{
// debug info
const std : : string tok3str_ ( tok3 - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " return " )
2009-07-20 14:39:24 +02:00
ret = true ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " { " || tok3->str() == " } " )
2009-07-20 14:39:24 +02:00
break ;
tok3 = tok3 - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( ! ret | | ! tok3 | | tok3 - > str ( ) ! = " } " )
2009-07-20 14:39:24 +02:00
break ;
- - indentlevel3 ;
continue ;
}
2009-07-19 16:51:31 +02:00
// Deallocating the struct..
2010-04-02 07:30:58 +02:00
else if ( indentlevel2 = = 0 & & Token : : Match ( tok3 , " free|kfree ( %varid% ) " , structid ) )
2009-07-19 16:51:31 +02:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tok3 , ( vartok - > str ( ) + " . " + tok2 - > strAt ( 2 ) ) . c_str ( ) , Malloc ) ;
2009-07-19 16:51:31 +02:00
break ;
}
// failed allocation => skip code..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " if ( ! %var% . %varid% ) " , structmemberid ) )
2009-07-19 16:51:31 +02:00
{
// Goto the ")"
2009-08-17 22:23:37 +02:00
tok3 = tok3 - > next ( ) - > link ( ) ;
2009-07-19 16:51:31 +02:00
2009-08-17 22:23:37 +02:00
// make sure we have ") {".. it should be
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok3 , " ) { " ) )
2009-08-17 22:23:37 +02:00
break ;
// Goto the "}"
tok3 = tok3 - > next ( ) - > link ( ) ;
2009-07-19 16:51:31 +02:00
}
2009-09-28 22:41:45 +02:00
// succeeded allocation
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " if ( %var% . %varid% ) { " , structmemberid))
2009-09-28 22:41:45 +02:00
{
// goto the ")"
tok3 = tok3 - > next ( ) - > link ( ) ;
// check if the variable is deallocated or returned..
unsigned int indentlevel4 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
2009-09-28 22:41:45 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok4 - > str ( ) = = " { " )
2009-09-28 22:41:45 +02:00
+ + indentlevel4 ;
2010-04-02 07:30:58 +02:00
else if ( tok4 - > str ( ) = = " } " )
2009-09-28 22:41:45 +02:00
{
- - indentlevel4 ;
2010-04-02 07:30:58 +02:00
if ( indentlevel4 = = 0 )
2009-09-28 22:41:45 +02:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok4 , " free|kfree ( %var% . %varid% ) " , structmemberid ) )
2009-09-28 22:41:45 +02:00
{
break ;
}
}
// was there a proper deallocation?
2010-04-02 07:30:58 +02:00
if ( indentlevel4 > 0 )
2009-09-28 22:41:45 +02:00
break ;
}
2009-07-19 16:51:31 +02:00
// Returning from function..
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " return " )
2009-07-19 16:51:31 +02:00
{
// Returning from function without deallocating struct member?
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok3 , " return %varid% ; " , structid ) )
2009-07-19 16:51:31 +02:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tok3 , ( vartok - > str ( ) + " . " + tok2 - > strAt ( 2 ) ) . c_str ( ) , Malloc ) ;
2009-07-19 16:51:31 +02:00
}
break ;
}
// goto isn't handled well.. bail out even though there might be leaks
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " goto " )
2009-07-19 16:51:31 +02:00
break ;
2009-07-22 08:30:51 +02:00
// using struct in a function call..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " %var% ( " ) )
2009-07-22 08:30:51 +02:00
{
// Calling non-function / function that doesn't deallocate?
2010-04-02 07:30:58 +02:00
if ( ignoredFunctions . find ( tok3 - > str ( ) ) ! = ignoredFunctions . end ( ) )
2009-07-22 08:30:51 +02:00
continue ;
// Check if the struct is used..
bool deallocated = false ;
unsigned int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
2009-07-22 08:30:51 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok4 - > str ( ) = = " ( " )
2009-07-22 08:30:51 +02:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok4 - > str ( ) = = " ) " )
2009-07-22 08:30:51 +02:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel < = 1 )
2009-07-22 08:30:51 +02:00
break ;
- - parlevel ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok4 , " [(,] %varid% [,)] " , structid ) )
2009-07-22 08:30:51 +02:00
{
/** @todo check if the function deallocates the memory */
deallocated = true ;
break ;
}
}
2010-04-02 07:30:58 +02:00
if ( deallocated )
2009-07-22 08:30:51 +02:00
break ;
}
2009-07-19 16:51:31 +02:00
}
}
}
}
}
}
2009-01-15 21:34:39 +01:00
2009-03-21 17:58:13 +01:00
2009-12-14 20:30:31 +01:00
2010-03-13 21:42:59 +01:00
/** @brief Experimental class for detecting memory leaks. The ExecutionPath functionality is used */
2009-12-14 20:30:31 +01:00
class CheckLocalLeaks : public ExecutionPath
{
public :
2010-03-13 21:42:59 +01:00
/** Startup constructor */
2009-12-21 18:17:35 +01:00
CheckLocalLeaks ( Check * c ) : ExecutionPath ( c , 0 ) , allocated ( false )
2009-12-14 20:30:31 +01:00
{
}
2010-03-13 21:42:59 +01:00
/** Debugging : print checks */
2009-12-14 20:30:31 +01:00
static void printOut ( const std : : list < ExecutionPath * > & checks )
{
std : : ostringstream ostr ;
ostr < < " CheckLocalLeaks::printOut " < < std : : endl ;
2010-04-02 07:30:58 +02:00
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-14 20:30:31 +01:00
{
CheckLocalLeaks * c = dynamic_cast < CheckLocalLeaks * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c )
2009-12-14 20:30:31 +01:00
{
2009-12-14 23:57:32 +01:00
ostr < < std : : hex < < c < < " : varId= " < < c - > varId < < " allocated= " < < ( c - > allocated ? " true " : " false " ) < < std : : endl ;
2009-12-14 20:30:31 +01:00
}
}
std : : cout < < ostr . str ( ) ;
}
private :
ExecutionPath * copy ( )
{
return new CheckLocalLeaks ( * this ) ;
}
/** start checking of given variable */
2009-12-21 18:17:35 +01:00
CheckLocalLeaks ( Check * c , unsigned int v , const std : : string & s ) : ExecutionPath ( c , v ) , allocated ( false ) , varname ( s )
2009-12-14 20:30:31 +01:00
{
}
2010-04-25 11:55:57 +02:00
/** is other execution path equal? */
bool is_equal ( const ExecutionPath * e ) const
{
const CheckLocalLeaks * c = static_cast < const CheckLocalLeaks * > ( e ) ;
return ( allocated = = c - > allocated & & varname = = c - > varname ) ;
}
2010-03-13 21:42:59 +01:00
/** Is variable allocated? */
2009-12-14 20:30:31 +01:00
bool allocated ;
2010-03-13 21:42:59 +01:00
/** Name of variable */
2009-12-14 20:30:31 +01:00
const std : : string varname ;
2010-03-13 21:42:59 +01:00
/** no implementation => compiler error if used */
2009-12-14 20:30:31 +01:00
void operator = ( const CheckLocalLeaks & ) ;
2010-03-13 21:42:59 +01:00
/** Allocation is detected */
2009-12-14 20:30:31 +01:00
static void alloc ( std : : list < ExecutionPath * > & checks , const unsigned int varid )
{
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-12-14 20:30:31 +01:00
return ;
std : : list < ExecutionPath * > : : iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-14 20:30:31 +01:00
{
CheckLocalLeaks * C = dynamic_cast < CheckLocalLeaks * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( C & & C - > varId = = varid )
2009-12-14 20:30:31 +01:00
C - > allocated = true ;
}
}
2010-03-13 21:42:59 +01:00
/** Deallocation is detected */
2009-12-14 20:30:31 +01:00
static void dealloc ( std : : list < ExecutionPath * > & checks , const Token * tok )
{
2010-04-02 07:30:58 +02:00
if ( tok - > varId ( ) = = 0 )
2009-12-14 20:30:31 +01:00
return ;
std : : list < ExecutionPath * > : : iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-14 20:30:31 +01:00
{
CheckLocalLeaks * C = dynamic_cast < CheckLocalLeaks * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( C & & C - > varId = = tok - > varId ( ) )
2009-12-14 20:30:31 +01:00
C - > allocated = false ;
}
}
2010-03-13 21:42:59 +01:00
/** return */
2010-04-04 11:24:52 +02:00
static void ret ( const std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-14 20:30:31 +01:00
{
std : : list < ExecutionPath * > : : const_iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-14 20:30:31 +01:00
{
CheckLocalLeaks * C = dynamic_cast < CheckLocalLeaks * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( C & & C - > allocated )
2009-12-14 20:30:31 +01:00
{
2009-12-22 23:21:52 +01:00
CheckMemoryLeakInFunction * checkMemleak = reinterpret_cast < CheckMemoryLeakInFunction * > ( C - > owner ) ;
2010-04-02 07:30:58 +02:00
if ( checkMemleak )
2009-12-22 21:56:00 +01:00
{
2010-05-16 19:55:16 +02:00
checkMemleak - > memleakError ( tok , C - > varname ) ;
2009-12-22 21:56:00 +01:00
break ;
}
2009-12-14 20:30:31 +01:00
}
}
}
2010-03-13 21:42:59 +01:00
/** parse the tokens */
2010-04-04 11:24:52 +02:00
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const
2009-12-14 20:30:31 +01:00
{
//std::cout << "CheckLocalLeaks::parse " << tok.str() << std::endl;
//printOut(checks);
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok . previous ( ) , " [;{}] " ) )
2009-12-14 20:30:31 +01:00
return & tok ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " %type% * %var% ; " ) )
2009-12-14 20:30:31 +01:00
{
const Token * vartok = tok . tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( vartok - > varId ( ) ! = 0 )
2009-12-21 18:17:35 +01:00
checks . push_back ( new CheckLocalLeaks ( owner , vartok - > varId ( ) , vartok - > str ( ) ) ) ;
2009-12-14 20:30:31 +01:00
return vartok - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " %var% = new " ) )
2009-12-14 20:30:31 +01:00
{
alloc ( checks , tok . varId ( ) ) ;
// goto end of statement
const Token * tok2 = & tok ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " ; " )
2009-12-14 20:30:31 +01:00
tok2 = tok2 - > next ( ) ;
return tok2 ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " delete %var% ; " ) )
2009-12-14 20:30:31 +01:00
{
dealloc ( checks , tok . next ( ) ) ;
return tok . tokAt ( 2 ) ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " delete [ ] %var% ; " ) )
2009-12-14 20:30:31 +01:00
{
dealloc ( checks , tok . tokAt ( 3 ) ) ;
return tok . tokAt ( 4 ) ;
}
2010-04-02 07:30:58 +02:00
if ( tok . str ( ) = = " return " )
2009-12-14 20:30:31 +01:00
{
2010-04-04 11:24:52 +02:00
ret ( checks , & tok ) ;
2009-12-14 20:30:31 +01:00
}
return & tok ;
}
2009-12-15 19:27:07 +01:00
/** going out of scope - all execution paths end */
2009-12-25 20:12:06 +01:00
void end ( const std : : list < ExecutionPath * > & checks , const Token * tok ) const
2009-12-15 19:27:07 +01:00
{
2010-04-04 11:24:52 +02:00
ret ( checks , tok ) ;
2009-12-15 19:27:07 +01:00
}
2009-12-14 20:30:31 +01:00
} ;
void CheckMemoryLeakInFunction : : localleaks ( )
{
2009-12-25 20:12:06 +01:00
// Check this scope..
CheckLocalLeaks c ( this ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
2009-12-14 20:30:31 +01:00
}