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
2015-01-03 12:14:58 +01:00
* Copyright ( C ) 2007 - 2015 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"
2011-12-23 22:31:48 +01:00
# include "symboldatabase.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2009-03-20 18:16:21 +01:00
# include "tokenize.h"
2015-08-03 09:20:50 +02:00
# include "astutils.h"
2009-03-20 18:16:21 +01:00
2009-01-15 21:34:39 +01:00
# include <algorithm>
# include <sstream>
2009-07-22 08:30:51 +02:00
# include <set>
2010-08-05 21:23:32 +02:00
# include <stack>
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)
2011-10-13 20:53:06 +02:00
namespace {
2011-11-25 14:47:45 +01:00
CheckMemoryLeakInFunction instance1 ;
2011-10-13 20:53:06 +02:00
CheckMemoryLeakInClass instance2 ;
CheckMemoryLeakStructMember instance3 ;
CheckMemoryLeakNoVar instance4 ;
2009-01-15 21:34:39 +01:00
}
2012-03-18 07:49:22 +01:00
/**
* Count function parameters
* \ param tok Function name token before the ' ( '
*/
static unsigned int countParameters ( const Token * tok )
{
tok = tok - > tokAt ( 2 ) ;
if ( tok - > str ( ) = = " ) " )
return 0 ;
unsigned int numpar = 1 ;
2014-02-15 16:17:25 +01:00
while ( nullptr ! = ( tok = tok - > nextArgument ( ) ) )
2012-03-18 07:49:22 +01:00
numpar + + ;
return numpar ;
}
2011-09-08 18:23:25 +02:00
/** List of functions that can be ignored when searching for memory leaks.
* These functions don ' t take the address of the given pointer
* This list needs to be alphabetically sorted so we can run bsearch on it .
2011-10-13 20:55:55 +02:00
* This list contains function names with const parameters e . g . : atof ( const char * )
2011-09-08 18:23:25 +02:00
* Reference : http : //www.aquaphoenix.com/ref/gnu_c_library/libc_492.html#SEC492
*/
2015-06-17 22:28:15 +02:00
static const std : : set < std : : string > call_func_white_list = make_container < std : : set < std : : string > > ( )
< < " _open " < < " _wopen " < < " access " < < " adjtime " < < " asctime " < < " asctime_r " < < " asprintf " < < " assert "
< < " atof " < < " atoi " < < " atol " < < " chdir " < < " chmod " < < " chown "
< < " clearerr " < < " creat " < < " ctime " < < " ctime_r " < < " execl " < < " execle "
< < " execlp " < < " execv " < < " execve " < < " fchmod " < < " fclose " < < " fcntl "
< < " fdatasync " < < " feof " < < " ferror " < < " fflush " < < " fgetc " < < " fgetpos " < < " fgets "
< < " flock " < < " fmemopen " < < " fnmatch " < < " fopen " < < " fopencookie " < < " for " < < " fprintf " < < " fputc " < < " fputs " < < " fread " < < " free "
< < " freopen " < < " fscanf " < < " fseek " < < " fseeko " < < " fsetpos " < < " fstat " < < " fsync " < < " ftell " < < " ftello "
< < " ftruncate " < < " fwrite " < < " getc " < < " getenv " < < " getgrnam " < < " gethostbyaddr " < < " gethostbyname " < < " getnetbyname "
< < " getopt " < < " getopt_long " < < " getprotobyname " < < " getpwnam " < < " gets " < < " getservbyname " < < " getservbyport "
< < " glob " < < " gmtime " < < " gmtime_r " < < " if " < < " index " < < " inet_addr " < < " inet_aton " < < " inet_network " < < " initgroups " < < " ioctl "
< < " link " < < " localtime " < < " localtime_r "
< < " lockf " < < " lseek " < < " lstat " < < " mblen " < < " mbstowcs " < < " mbtowc " < < " memchr " < < " memcmp " < < " memcpy " < < " memmove " < < " memset "
< < " mkdir " < < " mkfifo " < < " mknod " < < " mkstemp "
< < " obstack_printf " < < " obstack_vprintf " < < " open " < < " opendir " < < " parse_printf_format " < < " pathconf "
< < " perror " < < " popen " < < " posix_fadvise " < < " posix_fallocate " < < " pread "
< < " printf " < < " psignal " < < " puts " < < " pwrite " < < " qsort " < < " read " < < " readahead " < < " readdir " < < " readdir_r "
< < " readlink " < < " readv "
< < " realloc " < < " regcomp " < < " remove " < < " rename " < < " return " < < " rewind " < < " rewinddir " < < " rindex "
< < " rmdir " < < " scandir " < < " scanf " < < " seekdir "
< < " setbuf " < < " setbuffer " < < " sethostname " < < " setlinebuf " < < " setlocale " < < " setvbuf " < < " sizeof " < < " snprintf " < < " sprintf " < < " sscanf "
< < " stat " < < " stpcpy " < < " strcasecmp " < < " strcat " < < " strchr " < < " strcmp " < < " strcoll "
< < " strcpy " < < " strcspn " < < " strdup " < < " stricmp " < < " strlen " < < " strncasecmp " < < " strncat " < < " strncmp "
< < " strncpy " < < " strpbrk " < < " strrchr " < < " strspn " < < " strstr " < < " strtod " < < " strtok " < < " strtol " < < " strtoul " < < " strxfrm " < < " switch "
< < " symlink " < < " sync_file_range " < < " system " < < " telldir " < < " tempnam " < < " time " < < " typeid " < < " unlink "
< < " utime " < < " utimes " < < " vasprintf " < < " vfprintf " < < " vfscanf " < < " vprintf "
< < " vscanf " < < " vsnprintf " < < " vsprintf " < < " vsscanf " < < " while " < < " wordexp " < < " write " < < " writev " ;
2009-08-22 20:23:03 +02:00
2009-03-20 18:16:21 +01:00
//---------------------------------------------------------------------------
2009-01-15 21:34:39 +01:00
2012-09-11 19:19:11 +02:00
bool CheckMemoryLeak : : isclass ( const Token * tok , unsigned int varid ) 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 ;
2012-09-11 19:19:11 +02:00
const Variable * var = tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( varid ) ;
2011-03-07 20:17:52 +01:00
2011-07-15 02:45:27 +02:00
// return false if the type is a simple record type without side effects
// a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check base class for side effects */
/** @todo false negative: check constructors for side effects */
2013-03-05 13:33:38 +01:00
if ( var & & var - > typeScope ( ) & & var - > typeScope ( ) - > numConstructors = = 0 & &
( var - > typeScope ( ) - > varlist . empty ( ) | | var - > type ( ) - > needInitialization = = Type : : True ) & &
2013-03-05 15:28:40 +01:00
var - > type ( ) - > derivedFrom . empty ( ) )
2011-07-15 02:45:27 +02:00
return false ;
2009-01-15 21:34:39 +01:00
return true ;
}
//---------------------------------------------------------------------------
2012-09-11 18:03:47 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getAllocationType ( const Token * tok2 , unsigned int varid , std : : list < const Function * > * callstack ) 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);
2011-10-13 20:53:06 +02:00
if ( tok2 & & tok2 - > str ( ) = = " ( " ) {
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
2014-02-15 16:17:25 +01:00
tok2 = tok2 ? tok2 - > next ( ) : nullptr ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-01-15 21:34:39 +01:00
return No ;
2014-10-01 10:59:08 +02:00
if ( tok2 - > str ( ) = = " :: " )
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 - > isName ( ) )
2009-01-15 21:34:39 +01:00
return No ;
2015-01-31 10:50:39 +01:00
if ( ! Token : : Match ( tok2 , " %type%|%name% ::|. %type% " ) ) {
2013-01-22 21:33:39 +01:00
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
static const char * const mallocfunc [ ] = {
" malloc " ,
" calloc " ,
" strdup " ,
" strndup " ,
" kmalloc " ,
" kzalloc " ,
" kcalloc "
} ;
for ( unsigned int i = 0 ; i < sizeof ( mallocfunc ) / sizeof ( * mallocfunc ) ; i + + ) {
if ( tok2 - > str ( ) = = mallocfunc [ i ] )
return Malloc ;
}
2009-01-15 21:34:39 +01:00
2013-01-22 21:33:39 +01:00
// Using realloc..
if ( varid & & Token : : Match ( tok2 , " realloc ( %any% , " ) & & tok2 - > tokAt ( 2 ) - > varId ( ) ! = varid )
return Malloc ;
2009-01-15 21:34:39 +01:00
2013-01-22 21:33:39 +01:00
if ( Token : : Match ( tok2 , " new struct| %type% [;()] " ) | |
Token : : Match ( tok2 , " new ( std :: nothrow ) struct| %type% [;()] " ) | |
Token : : Match ( tok2 , " new ( nothrow ) struct| %type% [;()] " ) )
return New ;
2014-09-27 11:24:27 +02:00
if ( Token : : Match ( tok2 , " new struct| %type% *| [ " ) | |
Token : : Match ( tok2 , " new ( std :: nothrow ) struct| %type% *| [ " ) | |
Token : : Match ( tok2 , " new ( nothrow ) struct| %type% *| [ " ) )
2013-01-22 21:33:39 +01:00
return NewArray ;
if ( Token : : Match ( tok2 , " fopen|tmpfile|g_fopen ( " ) )
return File ;
2013-07-05 20:55:31 +02:00
if ( settings1 - > standards . posix ) {
2014-04-18 17:05:44 +02:00
if ( Token : : Match ( tok2 , " open|openat|creat|mkstemp|mkostemp|socket ( " ) ) {
2013-06-29 12:55:24 +02:00
// simple sanity check of function parameters..
// TODO: Make such check for all these functions
unsigned int num = countParameters ( tok2 ) ;
if ( tok2 - > str ( ) = = " open " & & num ! = 2 & & num ! = 3 )
return No ;
// is there a user function with this name?
2014-10-31 11:40:42 +01:00
if ( tok2 - > function ( ) )
2013-06-29 12:55:24 +02:00
return No ;
return Fd ;
}
2012-03-18 07:49:22 +01:00
2014-04-18 16:30:16 +02:00
if ( Token : : simpleMatch ( tok2 , " popen ( " ) )
return Pipe ;
}
2013-05-23 06:34:22 +02:00
2013-07-05 20:55:31 +02:00
// Does tok2 point on "g_malloc", "g_strdup", ..
2014-04-20 14:59:16 +02:00
const int alloctype = settings1 - > library . alloc ( tok2 ) ;
2014-03-17 16:10:54 +01:00
if ( alloctype > 0 ) {
if ( alloctype = = settings1 - > library . dealloc ( " free " ) )
return Malloc ;
2014-04-20 10:50:32 +02:00
if ( alloctype = = settings1 - > library . dealloc ( " fclose " ) )
return File ;
2013-07-08 18:26:18 +02:00
return Library : : ismemory ( alloctype ) ? OtherMem : OtherRes ;
2014-03-17 16:10:54 +01:00
}
2012-03-18 07:49:22 +01:00
}
2009-05-22 09:24:03 +02:00
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( tok2 , " %type%|%name% ::|. %type% " ) )
2013-01-22 21:33:39 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
2011-03-19 14:05:22 +01:00
// User function
2013-01-31 06:41:18 +01:00
const Function * func = tok2 - > function ( ) ;
2014-02-15 16:17:25 +01:00
if ( func = = nullptr )
2011-03-23 18:45:47 +01:00
return No ;
// Prevent recursion
2012-09-11 18:03:47 +02:00
if ( callstack & & std : : find ( callstack - > begin ( ) , callstack - > end ( ) , func ) ! = callstack - > end ( ) )
2011-03-23 18:45:47 +01:00
return No ;
2012-09-11 18:03:47 +02:00
std : : list < const Function * > cs ;
2011-03-23 18:45:47 +01:00
if ( ! callstack )
callstack = & cs ;
2012-09-11 18:03:47 +02:00
callstack - > push_back ( func ) ;
return functionReturnType ( func , callstack ) ;
2009-01-15 21:34:39 +01:00
}
2009-08-19 19:42:07 +02:00
2013-07-30 12:52:27 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getReallocationType ( const Token * tok2 , unsigned int varid )
2009-01-15 21:34:39 +01:00
{
// What we may have...
// * var = (char *)realloc(..;
2011-10-13 20:53:06 +02:00
if ( tok2 & & tok2 - > str ( ) = = " ( " ) {
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
2014-02-15 16:17:25 +01:00
tok2 = tok2 ? tok2 - > next ( ) : nullptr ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-01-15 21:34:39 +01:00
return No ;
2015-01-31 10:50:39 +01:00
if ( varid > 0 & & ! Token : : Match ( tok2 , " %name% ( %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..
2013-07-05 20:55:31 +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 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
{
2015-01-30 20:55:53 +01:00
if ( tokenizer - > isCPP ( ) ) {
if ( Token : : Match ( tok , " delete %varid% ; " , varid ) )
return New ;
2009-08-19 19:42:07 +02:00
2015-01-30 20:55:53 +01:00
if ( Token : : Match ( tok , " delete [ ] %varid% ; " , varid ) )
return NewArray ;
2009-08-19 19:42:07 +02:00
2015-01-30 20:55:53 +01:00
if ( Token : : Match ( tok , " delete ( %varid% ) ; " , varid ) )
return New ;
2009-08-19 19:42:07 +02:00
2015-01-30 20:55:53 +01:00
if ( Token : : Match ( tok , " delete [ ] ( %varid% ) ; " , varid ) )
return NewArray ;
}
2009-08-19 19:42:07 +02:00
2012-07-24 09:28:08 +02:00
if ( tok & & tok - > str ( ) = = " :: " )
tok = tok - > next ( ) ;
2012-07-27 12:25:20 +02:00
if ( Token : : Match ( tok , " free|kfree ( %varid% ) [;:] " , varid ) | |
2015-04-09 20:50:19 +02:00
Token : : Match ( tok , " free|kfree ( %varid% -|, " , varid ) | |
2011-08-31 05:42:11 +02:00
Token : : Match ( tok , " realloc ( %varid% , 0 ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return Malloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " fclose ( %varid% ) " , varid ) | |
2011-02-02 16:48:00 +01:00
Token : : simpleMatch ( tok , " fcloseall ( ) " ) )
2009-08-19 19:42:07 +02:00
return File ;
2013-07-05 20:55:31 +02:00
if ( settings1 - > standards . posix ) {
2013-06-29 12:55:24 +02:00
if ( Token : : Match ( tok , " close ( %varid% ) " , varid ) )
return Fd ;
2009-08-19 19:42:07 +02:00
2013-06-29 12:55:24 +02:00
if ( Token : : Match ( tok , " pclose ( %varid% ) " , varid ) )
return Pipe ;
}
2009-08-19 19:42:07 +02:00
2013-07-05 20:55:31 +02:00
// Does tok2 point on "g_free", etc ..
if ( Token : : Match ( tok , " %type% ( %varid% ) " , varid ) ) {
2014-04-20 14:59:16 +02:00
const int dealloctype = settings1 - > library . dealloc ( tok ) ;
2013-07-05 20:55:31 +02:00
if ( dealloctype > 0 )
2013-07-08 18:26:18 +02:00
return Library : : ismemory ( dealloctype ) ? OtherMem : OtherRes ;
2013-07-05 20:55:31 +02:00
}
2009-08-19 19:42:07 +02:00
return No ;
}
2010-12-07 07:07:36 +01:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getDeallocationType ( const Token * tok , const std : : string & varname ) const
2009-01-15 21:34:39 +01:00
{
2015-01-30 20:55:53 +01:00
if ( tokenizer - > isCPP ( ) ) {
if ( Token : : Match ( tok , std : : string ( " delete " + varname + " [,;] " ) . c_str ( ) ) )
return New ;
2009-01-15 21:34:39 +01:00
2015-01-30 20:55:53 +01:00
if ( Token : : Match ( tok , std : : string ( " delete [ ] " + varname + " [,;] " ) . c_str ( ) ) )
return NewArray ;
2009-01-15 21:34:39 +01:00
2015-01-30 20:55:53 +01:00
if ( Token : : Match ( tok , std : : string ( " delete ( " + varname + " ) [,;] " ) . c_str ( ) ) )
return New ;
2009-02-14 07:54:23 +01:00
2015-01-30 20:55:53 +01:00
if ( Token : : Match ( tok , std : : string ( " delete [ ] ( " + varname + " ) [,;] " ) . c_str ( ) ) )
return NewArray ;
}
2009-02-14 07:54:23 +01:00
2010-12-07 07:07:36 +01:00
if ( Token : : simpleMatch ( tok , std : : string ( " free ( " + varname + " ) ; " ) . c_str ( ) ) | |
2011-08-31 05:42:11 +02:00
Token : : simpleMatch ( tok , std : : string ( " kfree ( " + varname + " ) ; " ) . c_str ( ) ) | |
Token : : simpleMatch ( tok , std : : string ( " realloc ( " + varname + " , 0 ) ; " ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return Malloc ;
2010-12-07 07:07:36 +01:00
if ( Token : : simpleMatch ( tok , std : : string ( " fclose ( " + varname + " ) " ) . c_str ( ) ) | |
2010-04-02 07:30:58 +02:00
Token : : simpleMatch ( tok , " fcloseall ( ) " ) )
2009-05-21 12:16:42 +02:00
return File ;
2009-01-15 21:34:39 +01:00
2010-12-07 07:07:36 +01:00
if ( Token : : simpleMatch ( tok , std : : string ( " close ( " + varname + " ) " ) . c_str ( ) ) )
2009-06-21 17:01:43 +02:00
return Fd ;
2010-12-07 07:07:36 +01:00
if ( Token : : simpleMatch ( tok , std : : string ( " pclose ( " + varname + " ) " ) . c_str ( ) ) )
2009-05-21 12:16:42 +02:00
return Pipe ;
2009-01-15 21:34:39 +01:00
2013-07-05 20:55:31 +02:00
if ( Token : : Match ( tok , ( " %type% ( " + varname + " ) " ) . c_str ( ) ) ) {
2014-04-20 14:59:16 +02:00
int type = settings1 - > library . dealloc ( tok ) ;
2013-07-05 20:55:31 +02:00
if ( type > 0 )
2013-07-08 18:26:18 +02:00
return Library : : ismemory ( type ) ? OtherMem : OtherRes ;
2013-07-05 20:55:31 +02:00
}
2009-01-15 21:34:39 +01:00
return No ;
}
2010-12-07 07:07:36 +01:00
2009-01-15 21:34:39 +01:00
//--------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
//--------------------------------------------------------------------------
2011-11-30 19:43:02 +01: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 | |
2013-12-12 18:23:42 +01:00
alloctype = = CheckMemoryLeak : : OtherRes )
2011-12-08 21:28:34 +01:00
resourceLeakError ( tok , varname ) ;
2009-06-08 20:20:43 +02:00
else
2011-12-08 21:28:34 +01:00
memleakError ( tok , varname ) ;
2009-06-08 20:20:43 +02:00
}
//---------------------------------------------------------------------------
2015-04-25 17:48:11 +02:00
void CheckMemoryLeak : : reportErr ( const Token * tok , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg , unsigned int cwe ) 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
2015-04-25 17:48:11 +02:00
reportErr ( callstack , severity , id , msg , cwe ) ;
2009-07-13 15:07:26 +02:00
}
2015-04-25 17:48:11 +02:00
void CheckMemoryLeak : : reportErr ( const std : : list < const Token * > & callstack , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg , unsigned int cwe ) const
2009-07-13 15:07:26 +02:00
{
2015-04-25 17:48:11 +02:00
ErrorLogger : : ErrorMessage errmsg ( callstack , tokenizer ? & tokenizer - > list : 0 , severity , id , msg , false ) ;
errmsg . _cwe = cwe ;
2009-08-04 21:36:55 +02:00
2010-04-02 07:30:58 +02:00
if ( errorLogger )
2009-08-04 21:36:55 +02:00
errorLogger - > reportErr ( errmsg ) ;
else
2010-07-23 22:53:29 +02:00
Check : : reportError ( errmsg ) ;
2009-07-13 15:07:26 +02:00
}
2009-06-08 20:20:43 +02:00
2011-12-13 00:24:34 +01:00
void CheckMemoryLeak : : memleakError ( const Token * tok , const std : : string & varname ) const
2009-06-08 20:20:43 +02:00
{
2015-04-25 17:48:11 +02:00
reportErr ( tok , Severity : : error , " memleak " , " Memory leak: " + varname , 0U ) ;
2009-06-08 20:20:43 +02:00
}
2011-12-13 00:24:34 +01:00
void CheckMemoryLeak : : memleakUponReallocFailureError ( const Token * tok , const std : : string & varname ) const
2010-05-18 07:46:48 +02:00
{
2015-04-25 17:48:11 +02:00
reportErr ( tok , Severity : : error , " memleakOnRealloc " , " Common realloc mistake: \' " + varname + " \' nulled but not freed upon failure " , 0U ) ;
2010-05-18 07:46:48 +02:00
}
2012-05-17 10:33:24 +02:00
void CheckMemoryLeak : : resourceLeakError ( const Token * tok , const std : : string & varname ) const
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 ;
2015-04-25 17:48:11 +02:00
reportErr ( tok , Severity : : error , " resourceLeak " , errmsg , 775U ) ;
2009-06-08 20:20:43 +02:00
}
2011-12-13 00:24:34 +01:00
void CheckMemoryLeak : : deallocDeallocError ( const Token * tok , const std : : string & varname ) const
2009-06-08 20:20:43 +02:00
{
2015-04-25 17:48:11 +02:00
reportErr ( tok , Severity : : error , " deallocDealloc " , " Deallocating a deallocated pointer: " + varname , 0U ) ;
2009-06-08 20:20:43 +02:00
}
2011-12-13 00:24:34 +01:00
void CheckMemoryLeak : : deallocuseError ( const Token * tok , const std : : string & varname ) const
2009-06-08 20:20:43 +02:00
{
2015-04-25 17:48:11 +02:00
reportErr ( tok , Severity : : error , " deallocuse " , " Dereferencing ' " + varname + " ' after it is deallocated / released " , 0U ) ;
2009-06-08 20:20:43 +02:00
}
2011-12-13 00:24:34 +01:00
void CheckMemoryLeak : : mismatchSizeError ( const Token * tok , const std : : string & sz ) const
2009-06-08 20:20:43 +02:00
{
2015-04-25 17:48:11 +02:00
reportErr ( tok , Severity : : error , " mismatchSize " , " The allocated size " + sz + " is not a multiple of the underlying type's size. " , 0U ) ;
2009-06-08 20:20:43 +02:00
}
2011-12-13 00:24:34 +01:00
void CheckMemoryLeak : : mismatchAllocDealloc ( const std : : list < const Token * > & callstack , const std : : string & varname ) const
2009-06-08 20:20:43 +02:00
{
2015-04-25 17:48:11 +02:00
reportErr ( callstack , Severity : : error , " mismatchAllocDealloc " , " Mismatching allocation and deallocation: " + varname , 0U ) ;
2009-06-08 20:20:43 +02:00
}
2012-09-11 18:03:47 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : functionReturnType ( const Function * func , std : : list < const Function * > * callstack ) const
2009-06-15 17:44:59 +02:00
{
2015-01-08 05:45:31 +01:00
if ( ! func | | ! func - > hasBody ( ) )
2011-03-20 09:16:52 +01:00
return No ;
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 ;
2012-09-11 18:03:47 +02:00
for ( const Token * tok2 = func - > functionScope - > classStart ; tok2 ! = func - > functionScope - > classEnd ; tok2 = tok2 - > next ( ) ) {
2010-05-09 13:46:13 +02:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " } " ) {
2010-05-09 13:46:13 +02:00
if ( indentlevel < = 1 )
return No ;
2010-05-30 20:30:08 +02:00
- - indentlevel ;
2009-06-15 21:13:39 +02:00
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 , " return %name% ; " ) ) {
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 ;
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) = = " return " ) {
2011-03-23 18:45:47 +01:00
AllocType allocType = getAllocationType ( tok2 - > next ( ) , 0 , callstack ) ;
2010-05-09 13:46:13 +02:00
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 ;
2014-06-12 19:58:43 +02:00
// If variable is not local then alloctype shall be "No"
// Todo: there can be false negatives about mismatching allocation/deallocation.
// => Generate "alloc ; use ;" if variable is not local?
const Variable * var = tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( varid ) ;
if ( ! var | | ! var - > isLocal ( ) | | var - > isStatic ( ) )
return No ;
2012-06-25 20:00:50 +02:00
2010-05-09 13:46:13 +02:00
// Check if return pointer is allocated..
AllocType allocType = No ;
2012-09-11 18:03:47 +02:00
for ( const Token * tok = func - > functionScope - > classStart ; tok ! = func - > functionScope - > classEnd ; tok = tok - > next ( ) ) {
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " %varid% = " , varid ) ) {
2011-03-23 18:45:47 +01:00
allocType = getAllocationType ( tok - > tokAt ( 2 ) , varid , callstack ) ;
2010-12-29 22:18:23 +01:00
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " = %varid% ; " , varid ) ) {
2010-12-29 22:18:23 +01:00
return No ;
2009-06-15 21:13:39 +02:00
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " static %type% * %varid% [;{}=] " , varid ) ) {
2011-07-24 16:08:29 +02:00
return No ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " [(,] %varid% [,)] " , varid ) ) {
2011-03-24 17:14:12 +01:00
return No ;
}
2015-01-05 13:23:38 +01:00
if ( Token : : Match ( tok , " [(,] & %varid% [.,)] " , varid ) ) {
return No ;
}
if ( allocType = = No & & tok - > str ( ) = = " return " )
return No ;
2009-06-15 21:13:39 +02:00
}
2010-12-29 22:18:23 +01:00
return allocType ;
2009-06-15 17:44:59 +02:00
}
2009-06-08 20:20:43 +02:00
2009-11-14 09:06:28 +01:00
2012-05-03 10:43:47 +02:00
const char * CheckMemoryLeak : : functionArgAlloc ( const Function * func , unsigned int targetpar , AllocType & allocType ) const
2010-06-05 01:58:50 +02:00
{
2010-06-17 03:29:55 +02:00
allocType = No ;
2012-05-22 21:58:46 +02:00
if ( ! func | | ! func - > functionScope )
2012-04-21 23:05:37 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
2015-01-04 11:46:26 +01:00
if ( ! Token : : simpleMatch ( func - > retDef , " void " ) )
return " " ;
2012-05-03 10:43:47 +02:00
std : : list < Variable > : : const_iterator arg = func - > argumentList . begin ( ) ;
for ( ; arg ! = func - > argumentList . end ( ) ; + + arg ) {
if ( arg - > index ( ) = = targetpar - 1 )
2012-04-21 23:05:37 +02:00
break ;
2010-06-05 01:58:50 +02:00
}
2012-05-03 10:43:47 +02:00
if ( arg = = func - > argumentList . end ( ) )
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
2012-05-03 10:43:47 +02:00
// Is **
if ( ! arg - > isPointer ( ) )
return " " ;
const Token * tok = arg - > typeEndToken ( ) ;
tok = tok - > previous ( ) ;
if ( tok - > str ( ) ! = " * " )
return " " ;
2010-06-05 01:58:50 +02:00
// Check if pointer is allocated.
2010-06-17 03:29:55 +02:00
int realloc = 0 ;
2012-05-22 21:58:46 +02:00
for ( tok = func - > functionScope - > classStart ; tok & & tok ! = func - > functionScope - > classEnd ; tok = tok - > next ( ) ) {
2013-07-20 12:31:04 +02:00
if ( tok - > varId ( ) = = arg - > declarationId ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok - > tokAt ( - 3 ) , " free ( * %name% ) " ) ) {
2010-07-06 21:36:50 +02:00
realloc = 1 ;
allocType = No ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok - > previous ( ) , " * %name% = " ) ) {
2013-07-20 12:31:04 +02:00
allocType = getAllocationType ( tok - > tokAt ( 2 ) , arg - > declarationId ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( allocType = = No ) {
2013-07-20 12:31:04 +02:00
allocType = getReallocationType ( tok - > tokAt ( 2 ) , arg - > declarationId ( ) ) ;
2010-07-06 21:36:50 +02:00
}
2011-10-13 20:53:06 +02:00
if ( allocType ! = No ) {
2010-07-06 21:36:50 +02:00
if ( realloc )
return " realloc " ;
return " alloc " ;
}
2011-10-13 20:53:06 +02:00
} else {
2010-07-06 21:36:50 +02:00
// unhandled variable usage: bailout
return " " ;
2010-06-05 01:58:50 +02:00
}
}
}
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
}
2015-07-21 20:56:47 +02:00
static bool notvar ( const Token * tok , unsigned int varid )
2009-06-08 20:20:43 +02:00
{
2015-07-25 11:37:03 +02:00
if ( ! tok )
return false ;
2015-07-21 20:27:59 +02:00
if ( Token : : Match ( tok , " &&|; " ) )
return notvar ( tok - > astOperand1 ( ) , varid ) | | notvar ( tok - > astOperand2 ( ) , varid ) ;
2015-07-25 11:37:03 +02:00
if ( tok - > str ( ) = = " ( " & & Token : : Match ( tok - > astOperand1 ( ) , " UNLIKELY|LIKELY " ) )
return notvar ( tok - > astOperand2 ( ) , varid ) ;
2015-08-03 09:20:50 +02:00
const Token * vartok = astIsVariableComparison ( tok , " == " , " 0 " ) ;
2015-07-22 12:31:18 +02:00
return vartok & & ( vartok - > varId ( ) = = varid ) ;
2009-06-08 20:20:43 +02:00
}
2015-07-22 16:45:14 +02:00
static bool ifvar ( const Token * tok , unsigned int varid , const std : : string & comp , const std : : string & rhs )
{
if ( ! Token : : simpleMatch ( tok , " if ( " ) )
return false ;
2015-07-25 11:37:03 +02:00
const Token * condition = tok - > next ( ) - > astOperand2 ( ) ;
if ( condition & & condition - > str ( ) = = " ( " & & Token : : Match ( condition - > astOperand1 ( ) , " UNLIKELY|LIKELY " ) )
condition = condition - > astOperand2 ( ) ;
2015-07-22 16:45:14 +02:00
if ( ! condition | | condition - > str ( ) = = " && " )
return false ;
2015-07-25 11:37:03 +02:00
2015-08-03 09:20:50 +02:00
const Token * vartok = astIsVariableComparison ( condition , comp , rhs ) ;
2015-07-22 16:45:14 +02:00
return ( vartok & & vartok - > varId ( ) = = varid ) ;
}
2009-06-08 20:20:43 +02:00
2015-07-26 11:27:52 +02:00
static bool alwaysTrue ( const Token * tok )
{
if ( ! tok )
return false ;
if ( tok - > values . size ( ) = = 1U & &
tok - > values . front ( ) . intvalue ! = 0 & &
tok - > values . front ( ) . isKnown ( ) )
return true ;
if ( tok - > str ( ) = = " || " )
return alwaysTrue ( tok - > astOperand1 ( ) ) | | alwaysTrue ( tok - > astOperand2 ( ) ) ;
if ( tok - > str ( ) = = " true " )
return true ;
return ( tok - > isComparisonOp ( ) & &
tok - > values . size ( ) = = 1U & &
tok - > values . front ( ) . isKnown ( ) & &
tok - > values . front ( ) . intvalue ! = 0 ) ;
}
2009-06-08 20:20:43 +02:00
2015-01-30 20:55:53 +01:00
bool CheckMemoryLeakInFunction : : test_white_list ( const std : : string & funcname , const Settings * settings , bool cpp )
2014-02-05 08:18:39 +01:00
{
2015-06-17 22:28:15 +02:00
return ( ( call_func_white_list . find ( funcname ) ! = call_func_white_list . end ( ) ) | | ( settings - > library . leakignore . find ( funcname ) ! = settings - > library . leakignore . end ( ) ) | | ( cpp & & funcname = = " delete " ) ) ;
2014-02-05 08:18:39 +01:00
}
2010-06-05 01:58:50 +02:00
const char * CheckMemoryLeakInFunction : : call_func ( const Token * tok , std : : list < const Token * > callstack , const unsigned int varid , AllocType & alloctype , AllocType & dealloctype , bool & allocpar , unsigned int sz )
2009-01-15 21:34:39 +01:00
{
2015-01-30 20:55:53 +01:00
if ( test_white_list ( tok - > str ( ) , _settings , tokenizer - > isCPP ( ) ) ) {
2010-10-25 17:36:46 +02:00
if ( tok - > str ( ) = = " asprintf " | |
tok - > str ( ) = = " delete " | |
tok - > str ( ) = = " fclose " | |
tok - > str ( ) = = " for " | |
tok - > str ( ) = = " free " | |
tok - > str ( ) = = " if " | |
tok - > str ( ) = = " realloc " | |
tok - > str ( ) = = " return " | |
tok - > str ( ) = = " switch " | |
2014-04-06 18:45:24 +02:00
tok - > str ( ) = = " while " | |
tok - > str ( ) = = " sizeof " ) {
2010-10-25 17:36:46 +02:00
return 0 ;
}
2010-10-26 17:49:48 +02:00
// is the varid a parameter?
2012-03-16 19:52:18 +01:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ! = tok - > linkAt ( 1 ) ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ( " ) {
tok2 = tok2 - > nextArgument ( ) ;
if ( ! tok2 )
break ;
}
2011-10-13 20:53:06 +02:00
if ( tok2 - > varId ( ) = = varid ) {
2011-08-23 23:18:47 +02:00
if ( tok - > strAt ( - 1 ) = = " . " )
return " use " ;
else if ( tok2 - > strAt ( 1 ) = = " = " )
return " assign " ;
2013-12-14 07:37:24 +01:00
else if ( tok - > str ( ) = = " printf " )
return " use " ; // <- it is not certain printf dereference the pointer TODO: check the format string
2011-08-23 23:18:47 +02:00
else
2012-05-03 10:43:47 +02:00
return " use_ " ;
2011-08-23 23:18:47 +02:00
}
2010-10-26 17:49:48 +02:00
}
return 0 ;
2010-10-25 17:36:46 +02:00
}
2009-02-14 07:54:23 +01:00
2015-01-08 19:31:41 +01:00
if ( _settings - > library . isnoreturn ( tok ) & & tok - > strAt ( - 1 ) ! = " = " )
2009-11-14 09:06:28 +01:00
return " exit " ;
2014-04-20 10:50:32 +02:00
if ( varid > 0 & & ( 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_ " ;
2012-05-03 10:43:47 +02:00
const std : : string & funcname ( tok - > str ( ) ) ;
2011-10-13 20:53:06 +02:00
for ( std : : list < const Token * > : : const_iterator it = callstack . begin ( ) ; it ! = callstack . end ( ) ; + + it ) {
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..
2011-10-13 20:53:06 +02:00
if ( varid = = 0 ) {
2013-01-31 06:41:18 +01:00
const Function * func = tok - > function ( ) ;
2015-01-08 05:45:31 +01:00
if ( ! func | | ! func - > hasBody ( ) )
2009-10-03 21:46:22 +02:00
return 0 ;
2012-09-11 18:03:47 +02:00
Token * ftok = getcode ( func - > functionScope - > classStart - > next ( ) , callstack , 0 , alloctype , dealloctype , false , 1 ) ;
simplifycode ( ftok ) ;
2014-02-16 11:47:52 +01:00
const char * ret = nullptr ;
2012-09-11 18:03:47 +02:00
if ( Token : : simpleMatch ( ftok , " ; alloc ; } " ) )
2009-10-03 21:46:22 +02:00
ret = " alloc " ;
2012-09-11 18:03:47 +02:00
else if ( Token : : simpleMatch ( ftok , " ; dealloc ; } " ) )
2009-10-03 21:46:22 +02:00
ret = " dealloc " ;
2012-09-11 18:03:47 +02:00
TokenList : : deleteTokens ( ftok ) ;
2009-10-03 21:46:22 +02:00
return ret ;
}
2009-06-12 17:31:29 +02:00
// how many parameters is there in the function call?
2014-12-09 20:34:30 +01:00
const unsigned int numpar = countParameters ( tok ) ;
2011-11-26 21:02:04 +01:00
if ( numpar = = 0 ) {
2011-01-11 20:14:15 +01:00
// Taking return value => it is not a noreturn function
if ( tok - > strAt ( - 1 ) = = " = " )
2014-02-15 16:17:25 +01:00
return nullptr ;
2011-01-11 20:14:15 +01:00
// Function is not noreturn
2014-09-01 14:12:22 +02:00
if ( tok - > function ( ) & & tok - > function ( ) - > functionScope ) {
2014-09-01 13:54:33 +02:00
std : : string temp ;
if ( ! _settings - > library . isScopeNoReturn ( tok - > function ( ) - > functionScope - > classEnd , & temp ) & & temp . empty ( ) )
return nullptr ;
2015-01-08 19:31:41 +01:00
} else if ( _settings - > library . isnotnoreturn ( tok ) )
2014-02-15 16:17:25 +01:00
return nullptr ;
2011-01-11 20:14:15 +01:00
2012-05-03 10:43:47 +02:00
return " callfunc " ;
2011-01-11 20:14:15 +01:00
}
2009-06-12 17:31:29 +02:00
2011-12-10 11:55:14 +01:00
unsigned int par = 0 ;
2009-01-15 21:34:39 +01:00
2009-10-12 21:36:28 +02:00
const bool dot ( tok - > previous ( ) - > str ( ) = = " . " ) ;
2011-01-01 20:14:01 +01:00
const bool eq ( tok - > previous ( ) - > str ( ) = = " = " ) ;
2009-10-12 21:36:28 +02:00
2013-01-28 06:47:48 +01:00
const Token * functok = tok ;
2011-12-10 11:55:14 +01:00
tok = Token : : findsimplematch ( tok , " ( " ) ;
if ( tok )
tok = tok - > next ( ) ;
2009-01-15 21:34:39 +01:00
2011-12-10 11:55:14 +01:00
for ( ; tok ; tok = tok - > nextArgument ( ) ) {
+ + par ;
2014-11-18 06:38:19 +01:00
if ( Token : : Match ( tok , " %varid% [,()] " , varid ) ) {
2011-12-10 11:55:14 +01:00
if ( dot )
return " use " ;
2009-10-12 21:36:28 +02:00
2013-01-31 06:41:18 +01:00
const Function * function = functok - > function ( ) ;
2012-09-11 18:03:47 +02:00
if ( ! function )
2011-12-10 11:55:14 +01:00
return " use " ;
2009-06-12 17:31:29 +02:00
2011-12-10 11:55:14 +01:00
// how many parameters does the function want?
2012-09-11 18:03:47 +02:00
if ( numpar ! = function - > argCount ( ) ) // TODO: Handle default parameters
2011-12-10 11:55:14 +01:00
return " recursive " ;
2012-05-03 10:43:47 +02:00
2014-11-18 06:38:19 +01:00
if ( ! function - > functionScope )
return " use " ;
2012-05-03 10:43:47 +02:00
const Variable * param = function - > getArgumentVar ( par - 1 ) ;
if ( ! param | | ! param - > nameToken ( ) )
return " use " ;
2013-07-20 12:31:04 +02:00
Token * func = getcode ( function - > functionScope - > classStart - > next ( ) , callstack , param - > declarationId ( ) , alloctype , dealloctype , false , sz ) ;
2012-05-03 10:43:47 +02:00
//simplifycode(func);
2011-12-10 11:55:14 +01:00
const Token * func_ = func ;
while ( func_ & & func_ - > str ( ) = = " ; " )
func_ = func_ - > next ( ) ;
2014-02-16 11:47:52 +01:00
const char * ret = nullptr ;
2011-12-10 11:55:14 +01:00
/** @todo handle "goto" */
if ( Token : : findsimplematch ( func_ , " dealloc " ) )
ret = " dealloc " ;
else if ( Token : : findsimplematch ( func_ , " use " ) )
ret = " use " ;
else if ( Token : : findsimplematch ( func_ , " &use " ) )
ret = " &use " ;
2012-05-05 18:33:26 +02:00
TokenList : : deleteTokens ( func ) ;
2011-12-10 11:55:14 +01:00
return ret ;
}
2014-11-18 06:38:19 +01:00
if ( Token : : Match ( tok , " & %varid% [,()] " , varid ) ) {
2013-01-31 06:41:18 +01:00
const Function * func = functok - > function ( ) ;
2012-09-11 18:03:47 +02:00
if ( func = = 0 )
2012-05-03 10:43:47 +02:00
continue ;
2011-12-10 11:55:14 +01:00
AllocType a ;
2012-05-03 10:43:47 +02:00
const char * ret = functionArgAlloc ( func , par , a ) ;
2011-12-10 11:55:14 +01:00
if ( a ! = No ) {
if ( alloctype = = No )
alloctype = a ;
else if ( alloctype ! = a )
alloctype = Many ;
allocpar = true ;
2009-01-15 21:34:39 +01:00
return ret ;
}
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %varid% . %name% [,)] " , varid ) )
2011-12-10 11:55:14 +01:00
return " use " ;
2009-01-15 21:34:39 +01:00
}
2011-12-10 11:55:14 +01:00
return ( eq | | _settings - > experimental ) ? 0 : " callfunc " ;
2009-01-15 21:34:39 +01:00
}
2009-02-04 07:11:36 +01:00
2010-09-04 10:06:34 +02:00
static void addtoken ( Token * * rettail , const Token * tok , const std : : string & str )
{
( * rettail ) - > insertToken ( str ) ;
( * rettail ) = ( * rettail ) - > next ( ) ;
( * rettail ) - > linenr ( tok - > linenr ( ) ) ;
( * rettail ) - > fileIndex ( tok - > fileIndex ( ) ) ;
}
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
{
2011-01-10 19:35:06 +01:00
// variables whose value depends on if(!var). If one of these variables
// is used in a if-condition then generate "ifv" instead of "if".
std : : set < unsigned int > extravar ;
2009-01-15 21:34:39 +01:00
// The first token should be ";"
2012-09-04 15:29:51 +02:00
Token * rethead = new Token ( 0 ) ;
2010-09-04 10:06:34 +02:00
rethead - > str ( " ; " ) ;
rethead - > linenr ( tok - > linenr ( ) ) ;
rethead - > fileIndex ( tok - > fileIndex ( ) ) ;
2012-09-04 15:29:51 +02:00
Token * rettail = rethead ;
2009-01-15 21:34:39 +01:00
int indentlevel = 0 ;
int parlevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " { " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " { " ) ;
2009-01-15 21:34:39 +01:00
+ + indentlevel ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " } " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " } " ) ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 0 )
2009-01-15 21:34:39 +01:00
break ;
- - indentlevel ;
}
2011-01-16 09:56:04 +01:00
else 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 = = 0 & & tok - > str ( ) = = " ; " )
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " ; " ) ;
2009-01-15 21:34:39 +01:00
2011-01-16 09:56:04 +01:00
// Start of new statement.. check if the statement has anything interesting
2011-12-10 11:55:14 +01:00
if ( varid > 0 & & parlevel = = 0 & & Token : : Match ( tok , " [;{}] " ) ) {
2011-01-16 09:56:04 +01:00
if ( Token : : Match ( tok - > next ( ) , " [{};] " ) )
continue ;
// function calls are interesting..
const Token * tok2 = tok ;
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( tok2 - > next ( ) , " %name% . " ) )
2011-01-16 09:56:04 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 - > next ( ) , " %name% ( " ) )
2011-01-16 09:56:04 +01:00
;
else if ( Token : : Match ( tok - > next ( ) , " continue|break|return|throw|goto|do|else " ) )
;
2011-10-13 20:53:06 +02:00
else {
2014-02-16 11:47:52 +01:00
const Token * skipToToken = nullptr ;
2011-01-16 09:56:04 +01:00
// scan statement for interesting keywords / varid
2011-10-13 20:53:06 +02:00
for ( tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ; " ) {
2011-01-16 09:56:04 +01:00
// nothing interesting found => skip this statement
skipToToken = tok2 - > previous ( ) ;
break ;
}
2011-01-16 09:57:56 +01:00
if ( tok2 - > varId ( ) = = varid | |
2011-10-13 20:53:06 +02:00
tok2 - > str ( ) = = " : " | | tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " } " ) {
2011-01-16 09:56:04 +01:00
break ;
}
}
2011-01-16 09:57:56 +01:00
2011-10-13 20:53:06 +02:00
if ( skipToToken ) {
2011-01-16 09:56:04 +01:00
tok = skipToToken ;
continue ;
}
}
}
2011-10-13 20:53:06 +02:00
if ( varid = = 0 ) {
if ( ! callstack . empty ( ) & & Token : : Match ( tok , " [;{}] __cppcheck_lock|__cppcheck_unlock ( ) ; " ) ) {
2009-10-03 21:46:22 +02:00
// Type of leak = Resource leak
alloctype = dealloctype = CheckMemoryLeak : : File ;
2011-10-13 20:53:06 +02:00
if ( tok - > next ( ) - > str ( ) = = " __cppcheck_lock " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " alloc " ) ;
2011-10-13 20:53:06 +02:00
} else {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " 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
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if " ) ;
2009-10-03 21:46:22 +02:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
2009-08-29 07:02:36 +02:00
}
2011-10-13 20:53:06 +02:00
} else {
2011-06-29 20:00:21 +02:00
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " %varid% = close ( %varid% ) " , varid ) ) {
2011-06-29 20:00:21 +02:00
addtoken ( & rettail , tok , " dealloc " ) ;
addtoken ( & rettail , tok , " ; " ) ;
addtoken ( & rettail , tok , " assign " ) ;
addtoken ( & rettail , tok , " ; " ) ;
tok = tok - > tokAt ( 5 ) ;
continue ;
}
2009-10-03 21:46:22 +02:00
// var = strcpy|.. ( var ,
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " [;{}] %varid% = memcpy|memmove|memset|strcpy|strncpy|strcat|strncat ( %varid% , " , varid ) ) {
2011-11-20 14:22:39 +01:00
tok = tok - > linkAt ( 4 ) ;
2009-10-03 21:46:22 +02:00
continue ;
2009-02-07 11:54:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > previous ( ) , " [(;{}] %varid% = " , varid ) | |
2012-04-26 18:56:58 +02:00
Token : : Match ( tok , " asprintf|vasprintf ( & %varid% , " , varid ) ) {
2009-10-03 21:46:22 +02:00
CheckMemoryLeak : : AllocType alloc ;
2012-04-26 18:56:58 +02:00
if ( Token : : Match ( tok , " asprintf|vasprintf ( " ) ) {
2009-10-03 21:46:22 +02:00
// todo: check how the return value is used.
2011-10-13 20:53:06 +02:00
if ( ! Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) {
2012-05-05 18:33:26 +02:00
TokenList : : deleteTokens ( rethead ) ;
2009-10-03 21:46:22 +02:00
return 0 ;
}
alloc = Malloc ;
tok = tok - > next ( ) - > link ( ) ;
2011-10-13 20:53:06 +02:00
} else {
2009-10-03 21:46:22 +02:00
alloc = getAllocationType ( tok - > tokAt ( 2 ) , varid ) ;
}
2012-10-25 14:05:53 +02:00
//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% ) " ) & &
2011-10-13 20:53:06 +02:00
( MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) % long ( sz ) ) ! = 0 ) {
2009-10-03 21:46:22 +02:00
mismatchSizeError ( tok - > tokAt ( 4 ) , tok - > strAt ( 4 ) ) ;
}
2011-10-13 20:53:06 +02:00
if ( alloc = = CheckMemoryLeak : : No ) {
2009-10-03 21:46:22 +02:00
alloc = getReallocationType ( tok - > tokAt ( 2 ) , varid ) ;
2011-10-13 20:53:06 +02:00
if ( alloc ! = CheckMemoryLeak : : No ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " realloc " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2012-10-24 03:09:42 +02:00
//TODO: this assignment is redundant, should be fixed
2012-10-25 14:05:53 +02:00
//realloc = true;
2009-10-03 21:46:22 +02:00
tok = tok - > tokAt ( 2 ) ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% ( " ) )
2011-01-16 09:56:04 +01:00
tok = tok - > next ( ) - > link ( ) ;
2009-10-03 21:46:22 +02:00
continue ;
}
}
2009-02-20 07:28:18 +01:00
2010-05-16 07:15:31 +02:00
// don't check classes..
2011-10-13 20:53:06 +02:00
if ( alloc = = CheckMemoryLeak : : New ) {
if ( Token : : Match ( tok - > tokAt ( 2 ) , " new struct| %type% [(;] " ) ) {
2011-08-07 01:10:15 +02:00
const int offset = tok - > strAt ( 3 ) = = " struct " ? 1 : 0 ;
2012-09-11 19:19:11 +02:00
if ( isclass ( tok - > tokAt ( 3 + offset ) , varid ) ) {
2010-05-16 07:15:31 +02:00
alloc = No ;
2009-02-20 07:28:18 +01:00
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok - > tokAt ( 2 ) , " new ( nothrow ) struct| %type% " ) ) {
2011-08-07 01:10:15 +02:00
const int offset = tok - > strAt ( 6 ) = = " struct " ? 1 : 0 ;
2012-09-11 19:19:11 +02:00
if ( isclass ( tok - > tokAt ( 6 + offset ) , varid ) ) {
2010-07-05 14:01:25 +02:00
alloc = No ;
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok - > tokAt ( 2 ) , " new ( std :: nothrow ) struct| %type% " ) ) {
2011-08-07 01:10:15 +02:00
const int offset = tok - > strAt ( 8 ) = = " struct " ? 1 : 0 ;
2012-09-11 19:19:11 +02:00
if ( isclass ( tok - > tokAt ( 8 + offset ) , varid ) ) {
2010-07-05 14:01:25 +02:00
alloc = No ;
}
}
2011-05-19 19:41:18 +02:00
if ( alloc = = No & & alloctype = = No )
alloctype = CheckMemoryLeak : : New ;
2009-01-15 21:34:39 +01:00
}
2011-10-13 20:53:06 +02:00
if ( alloc ! = No ) {
2012-10-25 14:05:53 +02:00
//if (! realloc)
addtoken ( & rettail , tok , " 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
2011-10-13 20:53:06 +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 ;
2010-06-06 11:22:59 +02:00
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% = %type% ( " ) ) {
2011-11-20 14:22:39 +01:00
tok = tok - > linkAt ( 3 ) ;
2010-06-06 11:22:59 +02:00
continue ;
}
2009-10-03 21:46:22 +02:00
}
// assignment..
2011-10-13 20:53:06 +02:00
else {
2009-10-03 21:46:22 +02:00
// is the pointer in rhs?
bool rhs = false ;
2012-12-09 08:59:21 +01:00
bool trailingSemicolon = false ;
bool used = false ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ; " ) {
2012-12-09 08:59:21 +01:00
trailingSemicolon = true ;
2010-11-20 08:35:23 +01:00
if ( rhs )
tok = tok2 ;
2009-10-03 21:46:22 +02:00
break ;
2010-11-20 08:35:23 +01:00
}
2009-01-15 21:34:39 +01:00
2014-11-18 06:38:19 +01:00
if ( ! used & & ! rhs ) {
2012-12-09 08:59:21 +01:00
if ( Token : : Match ( tok2 , " [=+(,] %varid% " , varid ) ) {
2014-11-18 06:38:19 +01:00
if ( Token : : Match ( tok2 , " [(,] " ) ) {
2012-12-09 08:59:21 +01:00
used = true ;
addtoken ( & rettail , tok , " use " ) ;
addtoken ( & rettail , tok , " ; " ) ;
}
rhs = true ;
2011-08-28 11:28:14 +02:00
}
2009-10-03 21:46:22 +02:00
}
}
2012-12-09 08:59:21 +01:00
if ( ! used ) {
if ( ! rhs )
addtoken ( & rettail , tok , " assign " ) ;
else {
addtoken ( & rettail , tok , " use_ " ) ;
if ( trailingSemicolon )
addtoken ( & rettail , tok , " ; " ) ;
}
}
2010-11-20 08:35:23 +01:00
continue ;
2009-10-03 21:46:22 +02:00
}
2009-01-25 21:57:34 +01:00
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok - > previous ( ) , " %op%|;|{|}|) ::| %name% " ) | | ( Token : : Match ( tok - > previous ( ) , " ( ::| %name% " ) & & ( ! rettail | | rettail - > str ( ) ! = " loop " ) ) ) {
2012-07-27 12:25:20 +02:00
if ( Token : : Match ( tok , " %varid% ? " , varid ) )
tok = tok - > tokAt ( 2 ) ;
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 )
2012-10-24 03:09:42 +02:00
//TODO: this assignment is redundant, should be fixed
/*dealloc = No*/ ;
2010-01-07 21:36:51 +01:00
2011-10-13 20:53:06 +02:00
else if ( dealloc ! = No ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " 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 ;
2011-10-13 20:53:06 +02:00
if ( dealloc ! = Many & & alloctype ! = No & & alloctype ! = Many & & alloctype ! = dealloc ) {
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 ;
2011-01-16 09:57:56 +01:00
2011-01-16 09:56:04 +01:00
if ( tok - > strAt ( 2 ) = = " ( " )
2011-11-20 14:22:39 +01:00
tok = tok - > linkAt ( 2 ) ;
2009-10-03 21:46:22 +02:00
continue ;
2009-01-15 21:34:39 +01:00
}
}
2009-10-03 21:46:22 +02:00
// if else switch
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) ) {
if ( alloctype = = Fd ) {
2015-07-22 16:45:14 +02:00
if ( ifvar ( tok , varid , " > " , " -1 " ) | |
ifvar ( tok , varid , " >= " , " 0 " ) | |
ifvar ( tok , varid , " > " , " 0 " ) | |
ifvar ( tok , varid , " != " , " -1 " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if(var) " ) ;
2009-10-03 21:46:22 +02:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
2015-07-22 16:45:14 +02:00
} else if ( ifvar ( tok , varid , " == " , " -1 " ) | |
ifvar ( tok , varid , " < " , " 0 " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if(!var) " ) ;
2009-10-03 21:46:22 +02:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2009-02-01 16:47:36 +01:00
}
2009-01-15 21:34:39 +01:00
2015-07-22 16:45:14 +02:00
if ( ifvar ( tok , varid , " != " , " 0 " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " 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 ( ) ;
2011-01-16 09:56:04 +01:00
continue ;
2015-07-22 16:45:14 +02:00
} else if ( ifvar ( tok , varid , " == " , " 0 " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if(!var) " ) ;
2011-01-10 19:35:06 +01:00
// parse the if-body.
// if a variable is assigned then add variable to "extravar".
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > next ( ) - > link ( ) - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2011-01-10 19:35:06 +01:00
if ( tok2 - > str ( ) = = " { " )
tok2 = tok2 - > link ( ) ;
else if ( tok2 - > str ( ) = = " } " )
break ;
else if ( Token : : Match ( tok2 , " %var% = " ) )
extravar . insert ( tok2 - > varId ( ) ) ;
}
2011-01-16 09:56:04 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
2011-10-13 20:53:06 +02:00
} else {
2011-01-10 19:35:06 +01:00
// Check if the condition depends on var or extravar somehow..
2009-10-03 21:46:22 +02:00
bool dep = false ;
2012-05-03 10:43:47 +02:00
const Token * const end = tok - > linkAt ( 1 ) ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ! = end ; tok2 = tok2 - > next ( ) ) {
if ( Token : : Match ( tok2 , " close|pclose|fclose|closedir ( %varid% ) " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " dealloc " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2009-10-03 21:46:22 +02:00
dep = true ;
2009-01-15 21:34:39 +01:00
break ;
2011-11-30 20:07:56 +01:00
} else if ( alloctype = = Fd & & Token : : Match ( tok2 , " %varid% !=|>= " , varid ) ) {
2009-10-03 21:46:22 +02:00
dep = true ;
2012-05-03 10:43:47 +02:00
} else if ( Token : : Match ( tok2 , " ! %varid% " , varid ) ) {
2010-03-13 17:11:48 +01:00
dep = true ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok2 , " %name% ( " ) & & ! test_white_list ( tok2 - > str ( ) , _settings , tokenizer - > isCPP ( ) ) ) {
2010-05-24 19:28:27 +02:00
bool use = false ;
2012-05-03 10:43:47 +02:00
for ( const Token * tok3 = tok2 - > tokAt ( 2 ) ; tok3 ; tok3 = tok3 - > nextArgument ( ) ) {
if ( Token : : Match ( tok3 - > previous ( ) , " (|, &| %varid% ,|) " , varid ) ) {
2010-05-24 19:28:27 +02:00
use = true ;
break ;
}
}
2011-10-13 20:53:06 +02:00
if ( use ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2010-12-22 18:32:00 +01:00
dep = false ;
2010-05-24 19:28:27 +02:00
break ;
}
2011-11-30 20:07:56 +01:00
} else if ( tok2 - > varId ( ) & & extravar . find ( tok2 - > varId ( ) ) ! = extravar . end ( ) ) {
dep = true ;
2014-11-20 22:19:39 +01:00
} else if ( tok2 - > varId ( ) = = varid & &
( tok2 - > next ( ) - > isConstOp ( ) | | tok2 - > previous ( ) - > isConstOp ( ) ) )
2011-01-10 19:35:06 +01:00
dep = true ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
2015-07-21 20:56:47 +02:00
if ( notvar ( tok - > next ( ) - > astOperand2 ( ) , varid ) )
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if(!var) " ) ;
2015-07-21 20:56:47 +02:00
else
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , ( dep ? " ifv " : " if " ) ) ;
2010-03-13 17:11:48 +01:00
2011-01-16 09:56:04 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
2009-01-15 21:34:39 +01:00
}
}
}
2011-10-13 20:53:06 +02:00
if ( ( tok - > str ( ) = = " else " ) | | ( tok - > str ( ) = = " switch " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , tok - > str ( ) ) ;
2011-02-08 20:18:15 +01:00
if ( Token : : simpleMatch ( tok , " switch ( " ) )
2011-01-16 09:56:04 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
2009-01-15 21:34:39 +01:00
}
2011-10-13 20:53:06 +02:00
if ( ( tok - > str ( ) = = " case " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " case " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2011-01-16 09:56:04 +01:00
if ( Token : : Match ( tok , " case %any% : " ) )
tok = tok - > tokAt ( 2 ) ;
continue ;
2009-01-15 21:34:39 +01:00
}
2011-10-13 20:53:06 +02:00
if ( ( tok - > str ( ) = = " default " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " default " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2011-01-16 09:56:04 +01:00
continue ;
2009-01-15 21:34:39 +01:00
}
// Loops..
2011-10-13 20:53:06 +02:00
else if ( ( tok - > str ( ) = = " for " ) | | ( tok - > str ( ) = = " while " ) ) {
2012-04-21 23:05:37 +02:00
const Token * const end = tok - > linkAt ( 1 ) ;
2015-07-26 11:27:52 +02:00
if ( ( Token : : simpleMatch ( tok , " while ( " ) & & alwaysTrue ( tok - > next ( ) - > astOperand2 ( ) ) ) | |
2011-10-13 20:53:06 +02:00
Token : : simpleMatch ( tok , " for ( ; ; ) " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while1 " ) ;
2012-04-21 23:05:37 +02:00
tok = end ;
2009-09-27 21:49:07 +02:00
continue ;
}
2010-01-24 21:48:39 +01:00
2011-10-13 20:53:06 +02:00
else if ( varid & & getDeallocationType ( tok - > tokAt ( 2 ) , varid ) ! = No ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " dealloc " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2010-05-29 21:11:59 +02:00
}
2011-10-13 20:53:06 +02:00
else if ( alloctype = = Fd & & varid ) {
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " while ( 0 <= %varid% ) " , varid ) | |
2014-01-17 17:25:56 +01:00
Token : : Match ( tok , " while ( %varid% >= 0 ) " , varid ) | |
Token : : Match ( tok , " while ( %varid% != -1 ) " , varid ) | |
Token : : Match ( tok , " while ( -1 != %varid% ) " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(var) " ) ;
2012-04-21 23:05:37 +02:00
tok = end ;
2010-01-24 21:48:39 +01:00
continue ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " while ( %varid% == -1 ) " , varid ) | |
2014-01-17 17:25:56 +01:00
Token : : Match ( tok , " while ( -1 == %varid% ) " , varid ) | |
Token : : Match ( tok , " while ( %varid% < 0 ) " , varid ) | |
Token : : Match ( tok , " while ( 0 > %varid% ) " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(!var) " ) ;
2012-04-21 23:05:37 +02:00
tok = end ;
2010-01-24 21:48:39 +01:00
continue ;
}
}
2011-10-13 20:53:06 +02:00
else if ( varid & & Token : : Match ( tok , " while ( %varid% ) " , varid)) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(var) " ) ;
2012-04-21 23:05:37 +02:00
tok = end ;
2010-01-24 21:48:39 +01:00
continue ;
2015-07-21 20:27:59 +02:00
} else if ( varid & & Token : : simpleMatch ( tok , " while ( " ) & & notvar ( tok - > next ( ) - > astOperand2 ( ) , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(!var) " ) ;
2012-04-21 23:05:37 +02:00
tok = end ;
2010-01-24 21:48:39 +01:00
continue ;
}
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " loop " ) ;
2011-01-16 09:57:56 +01:00
2015-07-21 20:27:59 +02:00
if ( varid > 0 & & notvar ( tok - > next ( ) - > astOperand2 ( ) , varid ) )
addtoken ( & rettail , tok , " !var " ) ;
2011-01-16 09:57:56 +01:00
2011-01-16 09:56:04 +01:00
continue ;
2009-01-15 21:34:39 +01:00
}
2011-10-13 20:53:06 +02:00
if ( ( tok - > str ( ) = = " do " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " do " ) ;
2011-01-16 09:56:04 +01:00
continue ;
2009-10-03 21:46:22 +02:00
}
2009-01-15 21:34:39 +01:00
// continue / break..
2011-12-10 11:55:14 +01:00
else if ( tok - > str ( ) = = " continue " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " continue " ) ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " break " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " break " ) ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " goto " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " goto " ) ;
2009-01-15 21:34:39 +01:00
}
// Return..
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " return " ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " return " ) ;
2011-10-13 20:53:06 +02:00
if ( varid = = 0 ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " ; " ) ;
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..
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) , " std :: auto_ptr < " ) ) {
2012-04-21 23:05:37 +02:00
const Token * tok2 = tok - > linkAt ( 4 ) ;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " > ( %varid% ) " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
2009-04-28 20:01:35 +02:00
tok = tok2 - > tokAt ( 3 ) ;
}
}
2011-10-13 20:53:06 +02:00
else if ( varid & & Token : : Match ( tok , " return strcpy|strncpy|memcpy ( %varid% " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
2009-07-24 21:55:35 +02:00
tok = tok - > tokAt ( 2 ) ;
}
2011-10-13 20:53:06 +02:00
else {
2010-08-04 23:01:32 +02:00
bool use = false ;
2015-09-11 16:26:33 +02:00
std : : stack < const Token * > functions ;
2010-08-05 21:23:32 +02:00
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ; " ) {
2010-08-04 23:01:32 +02:00
tok = tok2 ;
2009-07-24 21:55:35 +02:00
break ;
2010-08-04 23:01:32 +02:00
}
2009-01-15 21:34:39 +01:00
2010-08-05 21:23:32 +02:00
if ( tok2 - > str ( ) = = " ( " )
2015-09-11 16:26:33 +02:00
functions . push ( tok2 - > previous ( ) ) ;
else if ( ! functions . empty ( ) & & tok2 - > str ( ) = = " ) " )
functions . pop ( ) ;
2010-08-05 21:23:32 +02:00
2011-10-13 20:53:06 +02:00
if ( tok2 - > varId ( ) = = varid ) {
2010-08-04 23:01:32 +02:00
// Read data..
if ( ! Token : : Match ( tok2 - > previous ( ) , " &|( " ) & &
2013-03-01 12:42:04 +01:00
tok2 - > strAt ( 1 ) = = " [ " ) {
2015-09-11 16:26:33 +02:00
;
} else if ( functions . empty ( ) | |
! test_white_list ( functions . top ( ) - > str ( ) , _settings , tokenizer - > isCPP ( ) ) | |
getDeallocationType ( functions . top ( ) , varid ) ) {
2010-08-04 23:01:32 +02:00
use = true ;
}
2009-01-15 21:34:39 +01:00
}
}
2010-08-04 23:01:32 +02:00
if ( use )
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2009-01-15 21:34:39 +01:00
}
}
// throw..
2015-06-20 22:49:28 +02:00
else if ( tokenizer - > isCPP ( ) & & Token : : Match ( tok , " try|throw|catch " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , tok - > str ( ) ) ;
2012-12-16 18:06:40 +01:00
if ( tok - > strAt ( 1 ) = = " ( " )
tok = tok - > next ( ) - > link ( ) ;
}
2009-01-15 21:34:39 +01:00
// Assignment..
2011-10-13 20:53:06 +02:00
if ( varid ) {
if ( Token : : simpleMatch ( tok , " = { " ) ) {
2012-04-21 23:05:37 +02:00
const Token * const end2 = tok - > linkAt ( 1 ) ;
2010-10-20 18:39:40 +02:00
bool use = false ;
2012-04-21 23:05:37 +02:00
for ( const Token * tok2 = tok ; tok2 ! = end2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) = = varid ) {
2010-10-20 18:39:40 +02:00
use = true ;
break ;
}
}
2011-10-13 20:53:06 +02:00
if ( use ) {
2010-10-20 18:39:40 +02:00
addtoken ( & rettail , tok , " use " ) ;
addtoken ( & rettail , tok , " ; " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " & %name% = %varid% ; " , varid ) ) {
2012-10-27 16:36:14 +02:00
while ( rethead - > next ( ) )
rethead - > deleteNext ( ) ;
return rethead ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [)=] %varid% [+;)] " , varid ) | |
2015-01-31 10:50:39 +01:00
( Token : : Match ( tok , " %name% + %varid% " , varid ) & &
2012-12-09 08:59:21 +01:00
tok - > strAt ( 3 ) ! = " [ " & &
tok - > strAt ( 3 ) ! = " . " ) | |
2012-11-30 07:08:16 +01:00
Token : : Match ( tok , " << %varid% ; " , varid ) | |
2010-06-21 18:43:28 +02:00
Token : : Match ( tok , " = strcpy|strcat|memmove|memcpy ( %varid% , " , varid ) | |
2015-01-31 10:50:39 +01:00
Token : : Match ( tok , " [;{}] %name% [ %varid% ] " , varid ) ) {
2010-11-29 19:53:34 +01:00
addtoken ( & rettail , tok , " use " ) ;
2015-03-24 08:22:26 +01:00
} else if ( Token : : Match ( tok - > previous ( ) , " ; | { | } | = | ( | , | % cop % % varid % . | [ " , varid)) {
2010-10-25 17:36:46 +02:00
// warning is written for "dealloc ; use_ ;".
// but this use doesn't affect the leak-checking
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use_ " ) ;
2009-08-25 21:44:19 +02:00
}
2009-01-15 21:34:39 +01:00
}
// Investigate function calls..
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% ( " ) ) {
2009-11-15 10:30:00 +01:00
// A function call should normally be followed by ";"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) ) {
if ( ! Token : : Match ( tok , " if|for|while|switch " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " exit " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2009-11-15 10:30:00 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
}
2010-09-03 07:18:01 +02:00
// Calling setjmp / longjmp => bail out
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok , " setjmp|longjmp " ) ) {
2010-09-03 07:18:01 +02:00
while ( rethead - > next ( ) )
rethead - > deleteNext ( ) ;
return rethead ;
}
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"
2010-12-15 18:45:53 +01:00
// The "::use" means that a member function was probably called but it wasn't analysed further
2011-10-13 20:53:06 +02:00
else if ( classmember ) {
2015-01-08 19:31:41 +01:00
if ( _settings - > library . isnoreturn ( tok ) )
2010-11-10 18:24:40 +01:00
addtoken ( & rettail , tok , " exit " ) ;
2015-01-30 20:55:53 +01:00
else if ( ! test_white_list ( tok - > str ( ) , _settings , tokenizer - > isCPP ( ) ) ) {
2012-04-21 23:05:37 +02:00
const Token * const end2 = tok - > linkAt ( 1 ) ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ! = end2 ; tok2 = tok2 - > next ( ) ) {
2011-10-13 20:53:06 +02:00
if ( tok2 - > varId ( ) = = varid ) {
2010-09-08 20:03:22 +02:00
addtoken ( & rettail , tok , " ::use " ) ;
2009-01-15 21:34:39 +01:00
break ;
2010-09-08 20:03:22 +02:00
}
2009-01-15 21:34:39 +01:00
}
}
}
2011-10-13 20:53:06 +02:00
else {
2015-01-31 10:50:39 +01:00
if ( varid > 0 & & Token : : Match ( tok , " %name% ( close|fclose|pclose ( %varid% ) ) ; " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " dealloc " ) ;
2009-10-04 13:10:08 +02:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-06-05 01:58:50 +02:00
bool allocpar = false ;
const char * str = call_func ( tok , callstack , varid , alloctype , dealloctype , allocpar , sz ) ;
2011-10-13 20:53:06 +02:00
if ( str ) {
if ( allocpar ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , str ) ;
2010-06-17 03:29:55 +02:00
tok = tok - > next ( ) - > link ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( varid = = 0 | | str ! = std : : string ( " alloc " ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , str ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %varid% = " , varid ) ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , str ) ;
2010-06-05 01:58:50 +02:00
}
2011-10-13 20:53:06 +02:00
} else if ( varid > 0 & &
getReallocationType ( tok , varid ) ! = No & &
tok - > tokAt ( 2 ) - > varId ( ) = = varid ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if " ) ;
addtoken ( & rettail , tok , " { " ) ;
addtoken ( & rettail , tok , " dealloc " ) ;
addtoken ( & rettail , tok , " ; " ) ;
addtoken ( & rettail , tok , " } " ) ;
2009-10-03 21:46:22 +02:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2009-01-15 21:34:39 +01:00
}
}
// Callback..
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " ( *| %name% " ) & & Token : : simpleMatch ( tok - > link ( ) , " ) ( " ) ) {
2011-03-06 09:42:16 +01:00
const Token * tok2 = tok - > next ( ) ;
if ( tok2 - > str ( ) = = " * " )
tok2 = tok2 - > next ( ) ;
tok2 = tok2 - > next ( ) ;
2009-01-15 21:34:39 +01:00
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( tok2 , " . %name% " ) )
2011-03-06 09:42:16 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
2009-01-15 21:34:39 +01:00
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " ) ( " ) ) {
for ( ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{] " ) )
2009-01-15 21:34:39 +01:00
break ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > varId ( ) = = varid ) {
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
2009-01-15 21:34:39 +01:00
break ;
}
}
}
}
// Linux lists..
2014-11-07 07:44:12 +01:00
if ( varid > 0 & & Token : : Match ( tok , " [=(,] & (| %varid% [.[,)] " , varid ) ) {
// Is variable passed to a "leak-ignore" function?
bool leakignore = false ;
if ( Token : : Match ( tok , " [(,] " ) ) {
const Token * parent = tok ;
while ( parent & & parent - > str ( ) ! = " ( " )
parent = parent - > astParent ( ) ;
if ( parent & & parent - > astOperand1 ( ) & & parent - > astOperand1 ( ) - > isName ( ) ) {
const std : : string & functionName = parent - > astOperand1 ( ) - > str ( ) ;
if ( _settings - > library . leakignore . find ( functionName ) ! = _settings - > library . leakignore . end ( ) )
leakignore = true ;
}
}
// Not passed to "leak-ignore" function, add "&use".
if ( ! leakignore )
addtoken ( & rettail , tok , " &use " ) ;
2009-01-15 21:34:39 +01:00
}
}
2011-10-13 20:53:06 +02:00
for ( Token * tok1 = rethead ; tok1 ; tok1 = tok1 - > next ( ) ) {
if ( Token : : simpleMatch ( tok1 , " callfunc alloc ; " ) ) {
2010-11-30 19:36:04 +01:00
tok1 - > deleteThis ( ) ;
tok1 - > insertToken ( " use " ) ;
tok1 - > insertToken ( " ; " ) ;
}
}
2009-01-15 21:34:39 +01:00
return rethead ;
}
2009-06-08 20:20:43 +02:00
2012-05-17 10:33:24 +02:00
void CheckMemoryLeakInFunction : : simplifycode ( Token * tok ) const
2009-01-15 21:34:39 +01:00
{
2015-06-28 17:54:48 +02:00
if ( _tokenizer - > isCPP ( ) ) {
2011-01-01 12:27:57 +01:00
// Replace "throw" that is not in a try block with "return"
int indentlevel = 0 ;
int trylevel = - 1 ;
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
2011-01-01 12:27:57 +01:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " } " ) {
2011-01-01 12:27:57 +01:00
- - indentlevel ;
if ( indentlevel < = trylevel )
trylevel = - 1 ;
2011-10-13 20:53:06 +02:00
} else if ( trylevel = = - 1 & & tok2 - > str ( ) = = " try " )
2011-01-01 12:27:57 +01:00
trylevel = indentlevel ;
else if ( trylevel = = - 1 & & tok2 - > str ( ) = = " throw " )
tok2 - > str ( " return " ) ;
2009-01-15 21:34:39 +01:00
}
}
2015-04-10 14:18:52 +02:00
const bool printExperimental = _settings - > experimental ;
2010-09-12 21:04:05 +02:00
// Insert extra ";"
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( ! tok2 - > previous ( ) | | Token : : Match ( tok2 - > previous ( ) , " [;{}] " ) ) {
2012-12-16 18:06:40 +01:00
if ( Token : : Match ( tok2 , " assign|callfunc|use assign|callfunc|use|} " ) ) {
2010-09-12 21:04:05 +02:00
tok2 - > insertToken ( " ; " ) ;
}
}
}
2010-04-27 20:43:31 +02:00
// remove redundant braces..
2011-10-13 20:53:06 +02:00
for ( Token * start = tok ; start ; start = start - > next ( ) ) {
if ( Token : : simpleMatch ( start , " ; { " ) ) {
2010-04-27 20:43:31 +02:00
// the "link" doesn't work here. Find the end brace..
unsigned int indent = 0 ;
2011-10-13 20:53:06 +02:00
for ( Token * end = start ; end ; end = end - > next ( ) ) {
2010-04-27 20:43:31 +02:00
if ( end - > str ( ) = = " { " )
+ + indent ;
2011-10-13 20:53:06 +02:00
else if ( end - > str ( ) = = " } " ) {
if ( indent < = 1 ) {
2011-01-01 13:28:34 +01:00
// If the start/end braces are redundant, delete them
2011-10-13 20:53:06 +02:00
if ( indent = = 1 & & Token : : Match ( end - > previous ( ) , " [;{}] } %any% " ) ) {
2010-04-27 20:43:31 +02:00
start - > deleteNext ( ) ;
end - > deleteThis ( ) ;
}
break ;
}
- - indent ;
}
}
}
}
2009-01-15 21:34:39 +01:00
// reduce the code..
2011-01-01 13:28:34 +01:00
// it will be reduced in N passes. When a pass completes without any
// simplifications the loop is done.
2009-01-15 21:34:39 +01:00
bool done = false ;
2011-10-13 20:53:06 +02:00
while ( ! done ) {
2009-06-20 13:58:30 +02:00
//tok->printOut("simplifycode loop..");
2009-01-15 21:34:39 +01:00
done = true ;
2010-09-11 20:49:24 +02:00
// reduce callfunc
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " callfunc " ) {
2010-09-11 20:49:24 +02:00
if ( ! Token : : Match ( tok2 - > previous ( ) , " [;{}] callfunc ; } " ) )
tok2 - > deleteThis ( ) ;
}
}
2011-01-01 13:28:34 +01:00
// If the code starts with "if return ;" then remove it
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " ;| if return ; " ) ) {
2011-12-05 15:50:11 +01:00
tok - > deleteNext ( ) ;
2010-09-12 21:41:13 +02:00
tok - > deleteThis ( ) ;
if ( tok - > str ( ) = = " return " )
tok - > deleteThis ( ) ;
if ( tok - > strAt ( 1 ) = = " else " )
tok - > deleteNext ( ) ;
}
2010-01-14 21:41:50 +01:00
// simplify "while1" contents..
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( Token : : simpleMatch ( tok2 , " while1 { " ) ) {
2010-04-06 22:17:23 +02:00
unsigned int innerIndentlevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( Token * tok3 = tok2 - > tokAt ( 2 ) ; tok3 ; tok3 = tok3 - > next ( ) ) {
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2010-04-06 22:17:23 +02:00
+ + innerIndentlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok3 - > str ( ) = = " } " ) {
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
}
2011-10-13 20:53:06 +02:00
while ( innerIndentlevel = = 0 & & Token : : Match ( tok3 , " [{};] if|ifv|else { continue ; } " ) ) {
2011-12-08 01:41:53 +01:00
tok3 - > deleteNext ( 5 ) ;
2012-03-16 19:52:18 +01:00
if ( tok3 - > strAt ( 1 ) = = " else " )
2010-01-14 21:41:50 +01:00
tok3 - > deleteNext ( ) ;
}
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 { if { dealloc ; return ; } } " ) ) {
2010-01-14 21:41:50 +01:00
tok2 - > str ( " ; " ) ;
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
tok2 - > tokAt ( 4 ) - > deleteNext ( 2 ) ;
2010-01-14 21:41:50 +01:00
}
}
}
2011-01-01 13:28:34 +01:00
// Main inner simplification loop
2014-02-15 16:17:25 +01:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 ? tok2 - > next ( ) : nullptr ) {
2009-01-15 21:34:39 +01:00
// Delete extra ";"
2011-10-13 20:53:06 +02:00
while ( Token : : Match ( tok2 , " [;{}] ; " ) ) {
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace "{ }" with ";"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " { } " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2010-01-10 20:03:46 +01:00
tok2 - > insertToken ( " ; " ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete braces around a single instruction..
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 - > next ( ) , " { %name% ; } " ) ) {
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 2 ) - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 - > next ( ) , " { %name% %name% ; } " ) ) {
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 3 ) - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-23 22:42:07 +02:00
// Reduce "if if|callfunc" => "if"
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 , " if if|callfunc " ) ) {
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
2011-04-20 17:16:09 +02:00
// outer/inner if blocks. Remove outer condition..
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if|if(var) { if return use ; } " )) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 4 ) - > deleteNext ( ) ;
2011-04-20 17:16:09 +02:00
done = false ;
}
2011-10-13 20:53:06 +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
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if ; !!else " ) ) {
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 ;"
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok2 - > next ( ) , " if %name% ; else % name % ; " ) &&
2011-12-05 15:50:11 +01:00
tok2 - > strAt ( 2 ) = = tok2 - > strAt ( 5 ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 4 ) ;
2009-09-26 07:19:22 +02:00
done = false ;
}
2010-11-27 11:09:42 +01:00
// Reduce "if continue ; if continue ;" => "if continue ;"
2011-10-13 20:53:06 +02:00
else if ( Token : : simpleMatch ( tok2 - > next ( ) , " if continue ; if continue ; " )) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2010-11-27 11:09:42 +01:00
done = false ;
}
2009-01-15 21:34:39 +01:00
// Reduce "if return ; alloc ;" => "alloc ;"
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if return ; alloc|return ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if alloc ; else return ; " ) ) {
2011-12-05 15:50:11 +01:00
// Remove "if"
tok2 - > deleteNext ( ) ;
// Remove "; else return"
2011-12-08 01:41:53 +01:00
tok2 - > next ( ) - > deleteNext ( 3 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2015-01-31 10:50:39 +01:00
// Reduce "if ; else %name% ;" => "if %name% ;"
else if ( Token : : Match ( tok2 - > next ( ) , " if ; else % name % ; " )) {
2011-12-08 01:41:53 +01:00
tok2 - > next ( ) - > deleteNext ( 2 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-08-29 16:27:16 +02:00
// Reduce "if ; else" => "if"
2011-10-13 20:53:06 +02:00
else if ( Token : : simpleMatch ( tok2 - > next ( ) , " if ; else " )) {
2011-12-08 01:41:53 +01:00
tok2 - > next ( ) - > deleteNext ( 2 ) ;
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 ;"
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if return ; else | if return | continue | break ; " )) {
2011-12-08 01:41:53 +01:00
tok2 - > tokAt ( 3 ) - > deleteNext ( 3 ) ;
2010-01-12 19:12:08 +01:00
done = false ;
}
// Reduce "if continue|break ; else|if return ;" => "if return ;"
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if continue|break ; if | else return ; " )) {
2011-12-08 01:41:53 +01:00
tok2 - > next ( ) - > deleteNext ( 3 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-11-27 11:09:42 +01:00
// Remove "else" after "if continue|break|return"
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if continue|break|return ; else " )) {
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 3 ) - > deleteNext ( ) ;
2010-11-27 11:09:42 +01:00
done = false ;
}
2009-09-01 20:02:28 +02:00
// Delete "if { dealloc|assign|use ; return ; }"
2011-11-30 20:07:56 +01:00
else if ( Token : : Match ( tok2 , " [;{}] if { dealloc|assign|use ; return ; } " ) & &
2011-12-03 09:53:36 +01:00
! Token : : findmatch ( tok , " if {| alloc ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 7 ) ;
2012-03-16 19:52:18 +01:00
if ( tok2 - > strAt ( 1 ) = = " else " )
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2011-08-02 09:04:13 +02:00
// Remove "if { dealloc ; callfunc ; } !!else|return"
else if ( Token : : Match ( tok2 - > next ( ) , " if { dealloc | assign ; callfunc ; } " ) &&
2011-10-13 20:53:06 +02:00
! Token : : Match ( tok2 - > tokAt ( 8 ) , " else|return " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 7 ) ;
2009-02-08 19:27:09 +01:00
done = false ;
}
2009-01-15 21:34:39 +01:00
continue ;
}
2010-01-24 21:48:39 +01:00
// Reduce "alloc while(!var) alloc ;" => "alloc ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc ; while(!var) alloc ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2010-01-19 19:08:03 +01:00
done = false ;
2010-03-13 17:11:48 +01:00
}
// Reduce "ifv return;" => "if return use;"
2011-10-13 20:53:06 +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..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] if(var) assign|dealloc|use ; !!else " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "; if(!var) alloc ; !!else" => "; dealloc ; alloc ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " ; if(!var) alloc ; !!else " ) ) {
2009-01-15 21:34:39 +01:00
// Remove the "if(!var)"
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
// Insert "dealloc ;" before the "alloc ;"
tok2 - > insertToken ( " ; " ) ;
tok2 - > insertToken ( " dealloc " ) ;
done = false ;
}
2011-12-05 15:50:11 +01:00
// Reduce "if(!var) exit ;" => ";"
2011-10-27 10:41:34 +02:00
if ( Token : : simpleMatch ( tok2 , " ; if(!var) exit ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2009-08-29 16:03:23 +02:00
done = false ;
}
2009-08-29 16:27:16 +02:00
// Reduce "if* ;"..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var)|if(!var)|ifv ; " ) ) {
2009-08-29 16:27:16 +02:00
// Followed by else..
2012-03-16 19:52:18 +01:00
if ( tok2 - > strAt ( 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"
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2011-10-13 20:53:06 +02:00
} else {
2011-03-09 19:53:59 +01:00
// remove the "if*"
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-08-29 16:27:16 +02:00
}
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "else ;" => ";"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " else ; " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-11-10 17:46:40 +01:00
// Reduce "while1 continue| ;" => "use ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " while1 if| continue| ; " ) ) {
2009-09-27 21:49:07 +02:00
tok2 - > str ( " use " ) ;
2010-12-08 21:02:02 +01:00
while ( tok2 - > strAt ( 1 ) ! = " ; " )
2010-11-10 17:46:40 +01:00
tok2 - > deleteNext ( ) ;
2009-09-27 21:49:07 +02:00
done = false ;
}
2010-01-14 21:41:50 +01:00
// Reduce "while1 if break ;" => ";"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 if break ; " ) ) {
2010-01-14 21:41:50 +01:00
tok2 - > str ( " ; " ) ;
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2010-01-14 21:41:50 +01:00
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete if block: "alloc; if return use ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " alloc ; if return use ; !!else " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 4 ) ;
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 ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc|dealloc|use|callfunc ; exit ; " ) ) {
2010-02-20 10:17:45 +01:00
tok2 - > deleteNext ( ) ;
2009-07-23 16:30:30 +02:00
done = false ;
}
// Reduce "alloc|dealloc|use ; if(var) exit ;"
2011-10-13 20:53:06 +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 ;"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " if exit ; " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-07-23 16:30:30 +02:00
tok2 - > deleteThis ( ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Remove the "if break|continue ;" that follows "dealloc ; alloc ;"
2015-04-10 14:18:52 +02:00
if ( ! printExperimental & & Token : : Match ( tok2 , " dealloc ; alloc ; if break|continue ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > tokAt ( 3 ) - > deleteNext ( 2 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:48:40 +02:00
// if break ; break ; => break ;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " [;{}] if break ; break ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2010-09-11 21:48:40 +02:00
done = false ;
}
2010-01-24 21:48:39 +01:00
// Reduce "do { dealloc ; alloc ; } while(var) ;" => ";"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " do { dealloc ; alloc ; } while(var) ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 8 ) ;
2010-01-24 21:48:39 +01:00
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 ;" */
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " do { alloc ; } " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 2 ) - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-26 07:19:22 +02:00
// Reduce "loop break ; => ";"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop break|continue ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2009-09-26 07:19:22 +02:00
done = false ;
}
2010-01-10 15:40:50 +01:00
// Reduce "loop|do ;" => ";"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " loop|do ; " ) ) {
2010-01-10 15:40:50 +01:00
tok2 - > deleteThis ( ) ;
2010-01-10 14:00:32 +01:00
done = false ;
}
2010-09-12 21:15:19 +02:00
// Reduce "loop if break|continue ; !!else" => ";"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop if break|continue ; !!else " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-12 21:15:19 +02:00
// Reduce "loop { if break|continue ; !!else" => "loop {"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " loop { if break|continue ; !!else " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > next ( ) - > deleteNext ( 3 ) ;
2010-09-12 21:15:19 +02:00
done = false ;
}
2009-09-15 22:26:38 +02:00
// Replace "do ; loop ;" with ";"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " ; loop ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:07:35 +02:00
// Replace "loop loop .." with "loop .."
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " loop loop " ) ) {
2010-08-02 23:04:23 +02:00
tok2 - > deleteThis ( ) ;
done = false ;
}
2009-01-17 08:55:40 +01:00
// Replace "loop if return ;" with "if return ;"
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " loop if return " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-01-17 08:55:40 +01:00
done = false ;
2009-01-15 21:34:39 +01:00
}
2010-08-02 22:14:51 +02:00
// Reduce "loop|while1 { dealloc ; alloc ; }"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " loop|while1 { dealloc ; alloc ; } " ) ) {
2010-08-02 22:14:51 +02:00
// delete "{"
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
// delete "loop|while1"
2010-08-02 22:14:51 +02:00
tok2 - > deleteThis ( ) ;
// delete "}"
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 3 ) - > deleteNext ( ) ;
2010-08-02 22:14:51 +02:00
done = false ;
}
2010-09-12 20:45:30 +02:00
// loop { use ; callfunc ; } => use ;
// assume that the "callfunc" is not noreturn
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " loop { use ; callfunc ; } " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 6 ) ;
2010-09-12 20:45:30 +02:00
tok2 - > str ( " use " ) ;
tok2 - > insertToken ( " ; " ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete if block in "alloc ; if(!var) return ;"
2011-10-27 10:41:34 +02:00
if ( Token : : simpleMatch ( tok2 , " alloc ; if(!var) return ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2015-01-31 10:50:39 +01:00
// Reduce "[;{}] return use ; %name%" => "[;{}] return use ;"
if ( Token : : Match ( tok2 , " [;{}] return use ; %name% " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > tokAt ( 3 ) - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if(var) return use ;" => "return use ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var) return use ; !!else " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
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 ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc ; dealloc ; alloc ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 4 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-08 19:22:03 +02:00
// use; dealloc; => dealloc;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] use ; dealloc ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:32:21 +02:00
// use use => use
2012-12-09 08:59:21 +01:00
while ( Token : : simpleMatch ( tok2 , " use use " ) ) {
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2010-09-11 21:32:21 +02:00
done = false ;
}
2012-12-09 08:59:21 +01:00
// use use_ => use
if ( Token : : simpleMatch ( tok2 , " use use_ " ) ) {
tok2 - > deleteNext ( ) ;
done = false ;
}
// use_ use => use
if ( Token : : simpleMatch ( tok2 , " use_ use " ) ) {
tok2 - > deleteThis ( ) ;
done = false ;
}
// use & use => use
while ( Token : : simpleMatch ( tok2 , " use & use " ) ) {
tok2 - > deleteNext ( 2 ) ;
done = false ;
}
// & use use => use
while ( Token : : simpleMatch ( tok2 , " & use use " ) ) {
tok2 - > deleteThis ( ) ;
tok2 - > deleteThis ( ) ;
done = false ;
}
2010-09-11 20:18:16 +02:00
// use; if| use; => use;
2011-10-13 20:53:06 +02:00
while ( Token : : Match ( tok2 , " [;{}] use ; if| use ; " ) ) {
2010-09-11 20:18:16 +02:00
Token * t = tok2 - > tokAt ( 2 ) ;
2012-10-19 13:34:44 +02:00
t - > deleteNext ( 2 + ( t - > str ( ) = = " if " ? 1 : 0 ) ) ;
2010-09-11 20:18:16 +02:00
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete first part in "use ; return use ;"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] use ; return use ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:07:35 +02:00
// try/catch
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " try ; catch exit ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 3 ) ;
2010-09-11 21:07:35 +02:00
tok2 - > deleteThis ( ) ;
2010-09-11 20:49:24 +02:00
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete second case in "case ; case ;"
2011-10-13 20:53:06 +02:00
while ( Token : : simpleMatch ( tok2 , " case ; case ; " ) ) {
2011-12-08 01:41:53 +01:00
tok2 - > deleteNext ( 2 ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace switch with if (if not complicated)
2011-10-13 20:53:06 +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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * _tok = tok2 - > tokAt ( 2 ) ; _tok ; _tok = _tok - > next ( ) ) {
2010-04-02 07:30:58 +02:00
if ( _tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
break ;
2011-10-13 20:53:06 +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 ) ;
2014-08-30 11:35:25 +02:00
incase = incase | | ( _tok - > str ( ) = = " case " ) ;
incase = incase & & ( _tok - > str ( ) ! = " break " & & _tok - > str ( ) ! = " return " ) ;
2009-01-15 21:34:39 +01:00
}
2011-10-13 20:53:06 +02:00
if ( ! incase & & valid ) {
2009-01-15 21:34:39 +01:00
done = false ;
tok2 - > str ( " ; " ) ;
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 - > next ( ) ;
bool first = true ;
2011-10-13 20:53:06 +02:00
while ( Token : : Match ( tok2 , " case|default " ) ) {
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 " : " } " ) ;
2011-10-13 20:53:06 +02:00
if ( first ) {
2009-01-15 21:34:39 +01:00
first = false ;
tok2 - > insertToken ( " { " ) ;
2011-10-13 20:53:06 +02:00
} else {
2009-01-15 21:34:39 +01:00
// 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 ( ) ;
}
2011-10-13 20:53:06 +02:00
while ( tok2 ) {
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 ( ) ;
}
2011-10-13 20:53:06 +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 ) ;
2011-10-13 20:53:06 +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"..
2015-04-10 14:18:52 +02:00
if ( done & & printExperimental ) {
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
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
2014-02-15 16:17:25 +01:00
if ( ( result = Token : : findsimplematch ( tokens , " loop alloc ; " ) ) ! = nullptr ) {
2009-08-23 15:48:25 +02:00
return result ;
}
2011-10-13 20:53:06 +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 ) ;
}
2014-02-15 16:17:25 +01:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; if|if(var)|ifv return ; " ) ) ! = nullptr ) {
2009-08-23 15:48:25 +02:00
return result - > tokAt ( 3 ) ;
}
2014-02-15 16:17:25 +01:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; alloc|assign|return callfunc| ; " ) ) ! = nullptr ) {
2009-08-23 15:48:25 +02:00
return result - > tokAt ( 2 ) ;
}
2014-02-15 16:17:25 +01:00
if ( ( result = Token : : findsimplematch ( tokens , " ; alloc ; if assign ; " ) ) ! = nullptr ) {
2010-09-27 17:53:10 +02:00
return result - > tokAt ( 4 ) ;
2009-09-01 19:33:17 +02:00
}
2014-02-15 16:17:25 +01:00
if ( ( ( result = Token : : findsimplematch ( tokens , " ; alloc ; if dealloc ; } " ) ) ! = nullptr ) & &
2011-10-13 20:53:06 +02:00
! result - > tokAt ( 7 ) ) {
2010-05-31 18:20:34 +02:00
return result - > tokAt ( 6 ) ;
}
2014-02-15 16:17:25 +01:00
if ( ( result = Token : : findsimplematch ( tokens , " alloc ; } " ) ) ! = nullptr ) {
if ( result - > tokAt ( 3 ) = = nullptr )
2009-08-23 15:48:25 +02:00
return result - > tokAt ( 2 ) ;
}
// No deallocation / usage => report leak at the last token
2011-10-13 20:53:06 +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
2010-12-15 18:45:53 +01:00
// not a leak if exit is called before the end of the function
2010-07-30 08:50:10 +02:00
if ( ! Token : : Match ( last - > tokAt ( - 2 ) , " exit|callfunc ; } " ) )
return last ;
2009-08-23 15:48:25 +02:00
}
2014-02-15 16:17:25 +01:00
return nullptr ;
2009-08-23 15:48:25 +02:00
}
2009-01-15 21:34:39 +01:00
// Check for memory leaks for a function variable.
2015-04-01 15:39:45 +02:00
void CheckMemoryLeakInFunction : : checkScope ( const Token * startTok , 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 ;
2015-04-01 15:39:45 +02:00
Token * tok = getcode ( startTok , 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
2014-02-15 16:17:25 +01:00
const bool use_addr = bool ( Token : : findsimplematch ( tok , " &use " ) ! = nullptr ) ;
2012-10-25 19:41:18 +02:00
2009-01-15 21:34:39 +01:00
// Simplify the code and check if freed memory is used..
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " [;{}] ; " ) )
2011-12-05 15:50:11 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
}
2014-02-15 16:17:25 +01:00
if ( ( result = Token : : findmatch ( tok , " [;{}] dealloc ; use_ ; " ) ) ! = nullptr ) {
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 ";"
2011-10-13 20:53:06 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
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-11-27 11:09:42 +01:00
else if ( Token : : simpleMatch ( tok2 , " loop use_ { " ) )
tok2 - > deleteNext ( ) ;
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 " ) ;
2011-10-13 20:53:06 +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
2011-10-27 10:54:50 +02:00
if ( Token : : findsimplematch ( tok , " alloc " ) = = 0 ) {
2012-05-05 18:33:26 +02:00
TokenList : : deleteTokens ( tok ) ;
2009-10-08 20:49:27 +02:00
return ;
}
2010-05-16 19:55:16 +02:00
simplifycode ( tok ) ;
2009-08-02 21:23:47 +02:00
2011-10-13 20:53:06 +02:00
if ( _settings - > debug & & _settings - > _verbose ) {
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
2011-10-27 10:54:50 +02:00
if ( Token : : findsimplematch ( tok , " alloc " ) = = 0 ) {
2012-05-05 18:33:26 +02:00
TokenList : : deleteTokens ( tok ) ;
2009-01-15 21:34:39 +01:00
return ;
}
2009-07-14 08:17:12 +02:00
/** @todo handle "goto" */
2011-10-27 10:54:50 +02:00
if ( Token : : findsimplematch ( tok , " goto " ) ) {
2012-05-05 18:33:26 +02:00
TokenList : : deleteTokens ( tok ) ;
2009-01-15 21:34:39 +01:00
return ;
}
2014-02-15 16:17:25 +01:00
if ( ( result = findleak ( tok ) ) ! = nullptr ) {
2011-11-30 19:43:02 +01:00
memoryLeak ( result , varname , alloctype ) ;
2009-01-15 21:34:39 +01:00
}
2014-02-15 16:17:25 +01:00
else if ( ! use_addr & & ( result = Token : : findsimplematch ( tok , " dealloc ; dealloc ; " ) ) ! = nullptr ) {
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..
2014-08-30 11:35:25 +02:00
else if ( tok & & _settings - > debugwarnings ) {
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 ;
2014-08-30 11:35:25 +02:00
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; dealloc ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; return use ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; use ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; use ; return ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; dealloc ; return ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " if alloc ; dealloc ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " if alloc ; return use ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " if alloc ; use ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; ifv return ; dealloc ; } " ) ;
noerr = noerr | | Token : : simpleMatch ( first , " alloc ; if return ; dealloc; } " ) ;
2009-01-15 21:34:39 +01:00
// Unhandled case..
2014-08-30 11:35:25 +02:00
if ( ! noerr ) {
2010-08-27 20:28:00 +02:00
std : : ostringstream errmsg ;
2011-01-04 03:40:31 +01:00
errmsg < < " inconclusive leak of " < < varname < < " : " ;
2012-05-03 10:43:47 +02:00
errmsg < < tok - > stringifyList ( false , false , false , false , false , 0 , 0 ) ;
2012-01-06 15:15:52 +01:00
reportError ( first , Severity : : debug , " debug " , errmsg . str ( ) ) ;
2009-01-15 21:34:39 +01:00
}
}
2012-05-05 18:33:26 +02:00
TokenList : : deleteTokens ( tok ) ;
2009-01-15 21:34:39 +01: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:
2010-05-18 20:08:27 +02:00
// a = malloc(10); a = realloc(a, 100);
2010-05-18 07:46:48 +02:00
//---------------------------------------------------------------------------
2013-07-31 16:02:37 +02:00
2012-03-16 19:52:18 +01:00
static bool isNoArgument ( const SymbolDatabase * symbolDatabase , unsigned int varid )
{
const Variable * var = symbolDatabase - > getVariableFromVarId ( varid ) ;
return var & & ! var - > isArgument ( ) ;
}
2010-05-18 07:46:48 +02:00
void CheckMemoryLeakInFunction : : checkReallocUsage ( )
{
2012-10-21 09:07:51 +02:00
// only check functions
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2010-12-08 07:49:01 +01:00
2011-10-11 22:07:14 +02:00
// Search for the "var = realloc(var, 100" pattern within this function
2012-03-16 19:52:18 +01:00
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2010-08-24 20:58:22 +02:00
if ( tok - > varId ( ) > 0 & &
2015-01-31 10:50:39 +01:00
Token : : Match ( tok , " %name% = realloc|g_try_realloc ( %name% , %any% " ) & &
2010-07-19 08:55:39 +02:00
tok - > varId ( ) = = tok - > tokAt ( 4 ) - > varId ( ) & &
2012-03-16 19:52:18 +01:00
isNoArgument ( symbolDatabase , tok - > varId ( ) ) ) {
2010-07-27 08:17:27 +02:00
// Check that another copy of the pointer wasn't saved earlier in the function
2015-01-31 10:50:39 +01:00
if ( Token : : findmatch ( scope - > classStart , " %name% = %varid% ; " , tok , tok - > varId ( ) ) | |
Token : : findmatch ( scope - > classStart , " [{};] %varid% = %name% [;=] " , tok , tok - > varId ( ) ) )
2011-01-13 07:33:46 +01:00
continue ;
2011-11-20 14:22:39 +01:00
const Token * tokEndRealloc = tok - > linkAt ( 3 ) ;
2011-01-13 07:33:46 +01:00
// Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
2015-07-22 12:31:18 +02:00
if ( Token : : simpleMatch ( tokEndRealloc - > next ( ) , " ; if ( " ) & &
notvar ( tokEndRealloc - > tokAt ( 3 ) - > astOperand2 ( ) , tok - > varId ( ) ) ) {
const Token * tokEndBrace = tokEndRealloc - > linkAt ( 3 ) - > linkAt ( 1 ) ;
if ( tokEndBrace & & _tokenizer - > IsScopeNoReturn ( tokEndBrace ) )
2011-01-13 07:33:46 +01:00
continue ;
}
memleakUponReallocFailureError ( tok , tok - > str ( ) ) ;
2011-11-20 15:09:57 +01:00
} else if ( tok - > next ( ) - > varId ( ) > 0 & &
2015-01-31 10:50:39 +01:00
( Token : : Match ( tok , " * %name% = realloc|g_try_realloc ( * %name% , %any% " ) & &
2012-03-16 19:52:18 +01:00
tok - > next ( ) - > varId ( ) = = tok - > tokAt ( 6 ) - > varId ( ) ) & &
isNoArgument ( symbolDatabase , tok - > next ( ) - > varId ( ) ) ) {
2011-10-11 22:07:14 +02:00
// Check that another copy of the pointer wasn't saved earlier in the function
2015-01-31 10:50:39 +01:00
if ( Token : : findmatch ( scope - > classStart , " %name% = * %varid% ; " , tok , tok - > next ( ) - > varId ( ) ) | |
Token : : findmatch ( scope - > classStart , " [{};] * %varid% = %name% [;=] " , tok , tok - > next ( ) - > varId ( ) ) )
2011-10-11 22:07:14 +02:00
continue ;
2011-11-20 14:22:39 +01:00
const Token * tokEndRealloc = tok - > linkAt ( 4 ) ;
2011-10-11 22:07:14 +02:00
// Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
2011-11-20 15:09:57 +01:00
if ( Token : : Match ( tokEndRealloc - > next ( ) , " ; if ( ! * %varid% ) { " , tok - > next ( ) - > varId ( ) ) ) {
2011-11-20 14:22:39 +01:00
const Token * tokEndBrace = tokEndRealloc - > linkAt ( 8 ) ;
2011-10-11 22:07:14 +02:00
if ( tokEndBrace & & Token : : simpleMatch ( tokEndBrace - > tokAt ( - 2 ) , " ) ; " ) & &
2015-01-31 10:50:39 +01:00
Token : : Match ( tokEndBrace - > linkAt ( - 2 ) - > tokAt ( - 2 ) , " {|}|; %name% ( " ) )
2011-10-11 22:07:14 +02:00
continue ;
}
2011-11-20 15:09:57 +01:00
memleakUponReallocFailureError ( tok - > next ( ) , tok - > strAt ( 1 ) ) ;
2011-10-11 22:07:14 +02:00
}
2010-05-18 07:46:48 +02:00
}
}
}
//---------------------------------------------------------------------------
2009-01-15 21:34:39 +01:00
//---------------------------------------------------------------------------
// Checks for memory leaks inside function..
//---------------------------------------------------------------------------
2012-05-03 10:43:47 +02:00
static bool isInMemberFunc ( const Scope * scope )
2009-01-15 21:34:39 +01:00
{
2012-05-03 10:43:47 +02:00
while ( scope - > nestedIn & & ! scope - > functionOf )
scope = scope - > nestedIn ;
2009-07-31 23:42:21 +02:00
2012-05-03 10:43:47 +02:00
return ( scope - > functionOf ! = 0 ) ;
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 ( )
{
2012-05-03 10:43:47 +02:00
// Check locking/unlocking of global resources..
2012-10-21 09:07:51 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2009-08-29 15:20:37 +02:00
2014-02-15 16:17:25 +01:00
checkScope ( scope - > classStart - > next ( ) , " " , 0 , scope - > functionOf ! = nullptr , 1 ) ;
2012-05-03 10:43:47 +02:00
}
// Check variables..
2014-09-28 09:47:11 +02:00
for ( unsigned int i = 1 ; i < symbolDatabase - > getVariableListSize ( ) ; i + + ) {
2012-05-03 10:43:47 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( i ) ;
if ( ! var | | ( ! var - > isLocal ( ) & & ! var - > isArgument ( ) ) | | var - > isStatic ( ) | | ! var - > scope ( ) )
continue ;
2012-07-17 16:28:34 +02:00
if ( var - > isReference ( ) )
2012-06-01 19:01:19 +02:00
continue ;
2012-05-03 10:43:47 +02:00
if ( ! var - > isPointer ( ) & & var - > typeStartToken ( ) - > str ( ) ! = " int " )
continue ;
2012-11-30 06:03:58 +01:00
// check for known class without implementation (forward declaration)
2013-03-05 13:33:38 +01:00
if ( var - > isPointer ( ) & & var - > type ( ) & & ! var - > typeScope ( ) )
2012-11-30 06:03:58 +01:00
continue ;
2012-05-03 10:43:47 +02:00
unsigned int sz = _tokenizer - > sizeOfType ( var - > typeStartToken ( ) ) ;
if ( sz < 1 )
sz = 1 ;
if ( var - > isArgument ( ) )
checkScope ( var - > scope ( ) - > classStart - > next ( ) , var - > name ( ) , i , isInMemberFunc ( var - > scope ( ) ) , sz ) ;
else
checkScope ( var - > nameToken ( ) , var - > name ( ) , i , isInMemberFunc ( var - > scope ( ) ) , sz ) ;
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
{
2011-01-16 18:13:54 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2009-01-15 21:34:39 +01:00
2012-10-21 09:07:51 +02:00
// only check classes and structures
const std : : size_t classes = symbolDatabase - > classAndStructScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < classes ; + + i ) {
const Scope * scope = symbolDatabase - > classAndStructScopes [ i ] ;
std : : list < Variable > : : const_iterator var ;
for ( var = scope - > varlist . begin ( ) ; var ! = scope - > varlist . end ( ) ; + + var ) {
if ( ! var - > isStatic ( ) & & var - > isPointer ( ) ) {
// allocation but no deallocation of private variables in public function..
const Token * tok = var - > typeStartToken ( ) ;
if ( tok - > isStandardType ( ) ) {
if ( var - > isPrivate ( ) )
2015-01-17 16:28:39 +01:00
checkPublicFunctions ( scope , var - > nameToken ( ) ) ;
2012-10-21 09:07:51 +02:00
2015-01-17 16:28:39 +01:00
variable ( scope , var - > nameToken ( ) ) ;
2012-10-21 09:07:51 +02:00
}
// known class?
2013-03-05 15:28:40 +01:00
else if ( var - > type ( ) ) {
2012-10-21 09:07:51 +02:00
// not derived?
2013-03-05 15:28:40 +01:00
if ( var - > type ( ) - > derivedFrom . empty ( ) ) {
2011-01-18 07:32:06 +01:00
if ( var - > isPrivate ( ) )
2015-01-17 16:28:39 +01:00
checkPublicFunctions ( scope , var - > nameToken ( ) ) ;
2010-11-25 21:04:49 +01:00
2015-01-17 16:28:39 +01:00
variable ( scope , var - > nameToken ( ) ) ;
2010-11-25 21:04:49 +01:00
}
2010-11-23 18:41:07 +01:00
}
}
2009-01-15 21:34:39 +01:00
}
}
}
2010-11-23 18:41:07 +01:00
2011-01-17 18:29:19 +01:00
void CheckMemoryLeakInClass : : variable ( const Scope * scope , const Token * tokVarname )
2009-01-15 21:34:39 +01:00
{
2012-04-23 15:23:01 +02:00
const std : : string & varname = tokVarname - > str ( ) ;
2012-04-26 18:56:58 +02:00
const unsigned int varid = tokVarname - > varId ( ) ;
2012-04-23 15:23:01 +02:00
const std : : string & classname = scope - > className ;
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 ;
2010-11-23 18:41:07 +01:00
// Inspect member functions
2011-01-17 18:29:19 +01:00
std : : list < Function > : : const_iterator func ;
2011-10-13 20:53:06 +02:00
for ( func = scope - > functionList . begin ( ) ; func ! = scope - > functionList . end ( ) ; + + func ) {
2013-04-10 21:57:22 +02:00
const bool constructor = func - > isConstructor ( ) ;
const bool destructor = func - > isDestructor ( ) ;
2015-01-08 05:45:31 +01:00
if ( ! func - > hasBody ( ) ) {
2013-02-24 08:14:25 +01:00
if ( destructor ) { // implementation for destructor is not seen => assume it deallocates all variables properly
deallocInDestructor = true ;
Dealloc = CheckMemoryLeak : : Many ;
}
continue ;
}
2012-03-16 19:52:18 +01:00
bool body = false ;
2012-05-22 21:58:46 +02:00
const Token * end = func - > functionScope - > classEnd ;
for ( const Token * tok = func - > arg - > link ( ) ; tok ! = end ; tok = tok - > next ( ) ) {
if ( tok = = func - > functionScope - > classStart )
2012-03-16 19:52:18 +01:00
body = true ;
2012-04-23 15:23:01 +02:00
else {
2012-03-16 19:52:18 +01:00
if ( ! body ) {
2012-04-26 18:56:58 +02:00
if ( ! Token : : Match ( tok , " :|, %varid% ( " , varid ) )
2009-03-14 20:19:36 +01:00
continue ;
}
2009-03-14 18:21:37 +01:00
// Allocate..
2012-04-26 18:56:58 +02:00
if ( ! body | | Token : : Match ( tok , " %varid% = " , varid ) ) {
2010-06-13 19:00:11 +02:00
// var1 = var2 = ...
// bail out
2012-03-16 19:52:18 +01:00
if ( tok - > strAt ( - 1 ) = = " = " )
2010-06-13 19:00:11 +02:00
return ;
// Foo::var1 = ..
2010-12-07 07:07:36 +01:00
// bail out when not same class
2012-03-16 19:52:18 +01:00
if ( tok - > strAt ( - 1 ) = = " :: " & &
2011-01-17 18:29:19 +01:00
tok - > strAt ( - 2 ) ! = scope - > className )
2010-06-13 19:00:11 +02:00
return ;
2012-03-16 19:52:18 +01:00
AllocType alloc = getAllocationType ( tok - > tokAt ( body ? 2 : 3 ) , 0 ) ;
2011-10-13 20:53:06 +02:00
if ( alloc ! = CheckMemoryLeak : : No ) {
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
2011-10-13 20:53:06 +02:00
if ( alloc ! = CheckMemoryLeak : : Many & & Dealloc ! = CheckMemoryLeak : : No & & Dealloc ! = CheckMemoryLeak : : Many & & Dealloc ! = alloc ) {
2015-08-15 19:46:31 +02:00
std : : list < const Token * > callstack ;
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
}
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
2012-03-16 19:52:18 +01:00
if ( ! body )
2009-03-14 20:19:36 +01:00
continue ;
2009-03-14 18:21:37 +01:00
// Deallocate..
2010-12-07 07:07:36 +01:00
AllocType dealloc = getDeallocationType ( tok , varname ) ;
2011-10-13 20:53:06 +02:00
if ( dealloc = = No ) {
2011-01-17 18:29:19 +01:00
std : : string temp = scope - > className + " :: " + varname ;
2010-12-07 07:07:36 +01:00
dealloc = getDeallocationType ( tok , temp ) ;
}
2011-10-13 20:53:06 +02:00
if ( dealloc = = No ) {
2010-12-07 07:07:36 +01:00
std : : string temp = " this . " + varname ;
dealloc = getDeallocationType ( tok , temp ) ;
2009-03-14 18:21:37 +01:00
}
2011-11-28 20:08:29 +01:00
// some usage in the destructor => assume it's related
// to deallocation
if ( destructor & & tok - > str ( ) = = varname )
dealloc = CheckMemoryLeak : : Many ;
2011-10-13 20:53:06 +02:00
if ( dealloc ! = CheckMemoryLeak : : No ) {
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
2011-10-13 20:53:06 +02:00
if ( dealloc ! = CheckMemoryLeak : : Many & & Alloc ! = CheckMemoryLeak : : No & & Alloc ! = Many & & Alloc ! = dealloc ) {
2015-08-15 19:46:31 +02:00
std : : list < const Token * > callstack ;
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
}
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
2010-06-16 19:28:47 +02:00
// Function call .. possible deallocation
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok - > previous ( ) , " [ { } ; ] % name % ( " )) {
2015-01-30 20:55:53 +01:00
if ( ! CheckMemoryLeakInFunction : : test_white_list ( tok - > str ( ) , _settings , tokenizer - > isCPP ( ) ) ) {
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
}
}
2011-10-13 20:53:06 +02:00
if ( allocInConstructor & & ! deallocInDestructor ) {
2012-09-10 17:27:41 +02:00
unsafeClassError ( tokVarname , classname , classname + " :: " + varname /*, Alloc*/ ) ;
2011-10-13 20:53:06 +02:00
} else if ( Alloc ! = CheckMemoryLeak : : No & & Dealloc = = CheckMemoryLeak : : No ) {
2012-09-10 17:27:41 +02:00
unsafeClassError ( tokVarname , classname , classname + " :: " + varname /*, Alloc*/ ) ;
2009-01-15 21:34:39 +01:00
}
}
2012-09-10 17:27:41 +02:00
void CheckMemoryLeakInClass : : unsafeClassError ( const Token * tok , const std : : string & classname , const std : : string & varname )
{
2015-04-06 11:40:45 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
2012-09-10 17:27:41 +02:00
reportError ( tok , Severity : : style , " unsafeClassCanLeak " ,
" Class ' " + classname + " ' is unsafe, ' " + varname + " ' can leak by wrong usage. \n "
" The class ' " + classname + " ' is unsafe, wrong usage can cause memory/resource leaks for ' " + varname + " '. This can for instance be fixed by adding proper cleanup in the destructor. " ) ;
}
2009-01-15 21:34:39 +01:00
2011-01-17 18:29:19 +01:00
void CheckMemoryLeakInClass : : checkPublicFunctions ( const Scope * scope , const Token * classtok )
2010-05-15 19:40:32 +02:00
{
// 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.
2013-03-03 11:41:59 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
2010-05-15 19:40:32 +02:00
return ;
2009-01-15 21:34:39 +01:00
2010-11-25 21:04:49 +01:00
const unsigned int varid = classtok - > varId ( ) ;
2012-03-14 18:54:34 +01:00
if ( varid = = 0 ) {
_tokenizer - > getSymbolDatabase ( ) - > debugMessage ( classtok , " CheckMemoryInClass::checkPublicFunctions found variable \' " + classtok - > str ( ) + " \' with varid 0 " ) ;
2012-01-30 06:15:41 +01:00
return ;
2012-03-14 18:54:34 +01:00
}
2010-11-25 21:04:49 +01:00
2010-05-15 19:40:32 +02:00
// Parse public functions..
// If they allocate member variables, they should also deallocate
2011-01-17 18:29:19 +01:00
std : : list < Function > : : const_iterator func ;
2009-01-15 21:34:39 +01:00
2011-10-13 20:53:06 +02:00
for ( func = scope - > functionList . begin ( ) ; func ! = scope - > functionList . end ( ) ; + + func ) {
2012-05-29 21:13:34 +02:00
if ( ( func - > type = = Function : : eFunction | | func - > type = = Function : : eOperatorEqual ) & &
2015-01-08 05:45:31 +01:00
func - > access = = Public & & func - > hasBody ( ) ) {
2015-08-16 14:22:46 +02:00
const Token * tok2 = func - > functionScope - > classStart - > next ( ) ;
if ( Token : : Match ( tok2 , " %varid% = " , varid ) ) {
const CheckMemoryLeak : : AllocType alloc = getAllocationType ( tok2 - > tokAt ( 2 ) , varid ) ;
2010-11-25 21:04:49 +01:00
if ( alloc ! = CheckMemoryLeak : : No )
2015-08-16 14:22:46 +02:00
publicAllocationError ( tok2 , tok2 - > str ( ) ) ;
} else if ( Token : : Match ( tok2 , " %type% :: %varid% = " , varid ) & &
tok2 - > str ( ) = = scope - > className ) {
const CheckMemoryLeak : : AllocType alloc = getAllocationType ( tok2 - > tokAt ( 4 ) , varid ) ;
2010-12-07 07:07:36 +01:00
if ( alloc ! = CheckMemoryLeak : : No )
2015-08-16 14:22:46 +02:00
publicAllocationError ( tok2 , tok2 - > strAt ( 2 ) ) ;
2010-12-07 07:07:36 +01:00
}
2010-05-15 19:40:32 +02:00
}
}
}
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 )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " publicAllocationError " , " Possible leak in public function. The pointer ' " + varname + " ' is not deallocated before it is allocated. " ) ;
2010-05-15 19:40:32 +02:00
}
2009-01-15 21:34:39 +01:00
2009-07-19 16:51:31 +02:00
void CheckMemoryLeakStructMember : : check ( )
2011-05-11 18:19:14 +02:00
{
2012-05-03 10:43:47 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2014-09-28 09:47:11 +02:00
for ( unsigned int i = 1 ; i < symbolDatabase - > getVariableListSize ( ) ; i + + ) {
2012-05-03 10:43:47 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( i ) ;
if ( ! var | | ! var - > isLocal ( ) | | var - > isStatic ( ) )
2011-05-11 18:19:14 +02:00
continue ;
2012-05-03 10:43:47 +02:00
if ( var - > typeEndToken ( ) - > isStandardType ( ) )
continue ;
checkStructVariable ( var ) ;
2011-05-11 18:19:14 +02:00
}
}
2012-05-03 10:43:47 +02:00
bool CheckMemoryLeakStructMember : : isMalloc ( const Variable * variable )
2011-05-11 18:19:14 +02:00
{
2013-07-20 12:31:04 +02:00
const unsigned int declarationId ( variable - > declarationId ( ) ) ;
2011-05-11 18:19:14 +02:00
bool alloc = false ;
2013-09-21 18:10:29 +02:00
for ( const Token * tok2 = variable - > nameToken ( ) ; tok2 & & tok2 ! = variable - > scope ( ) - > classEnd ; tok2 = tok2 - > next ( ) ) {
2013-07-20 12:31:04 +02:00
if ( Token : : Match ( tok2 , " = %varid% [;=] " , declarationId ) ) {
2011-05-11 18:19:14 +02:00
return false ;
2013-07-20 12:31:04 +02:00
} else if ( Token : : Match ( tok2 , " %varid% = malloc|kmalloc ( " , declarationId ) ) {
2011-05-11 18:19:14 +02:00
alloc = true ;
}
}
return alloc ;
}
2015-06-20 22:26:51 +02:00
namespace {
static const std : : set < std : : string > ignoredFunctions = make_container < std : : set < std : : string > > ( )
< < " if "
< < " for "
< < " while "
< < " malloc "
;
}
2011-05-11 18:19:14 +02:00
2012-05-03 10:43:47 +02:00
void CheckMemoryLeakStructMember : : checkStructVariable ( const Variable * const variable )
2009-07-19 16:51:31 +02:00
{
2011-05-11 18:19:14 +02:00
// Is struct variable a pointer?
2012-05-03 10:43:47 +02:00
if ( variable - > isPointer ( ) ) {
2011-05-11 18:19:14 +02:00
// Check that variable is allocated with malloc
2012-05-03 10:43:47 +02:00
if ( ! isMalloc ( variable ) )
2011-05-11 18:19:14 +02:00
return ;
2011-12-10 11:55:14 +01:00
} else if ( ! _tokenizer - > isC ( ) ) {
// For non-C code a destructor might cleanup members
return ;
2011-05-11 18:19:14 +02:00
}
2009-09-28 22:58:06 +02:00
2011-05-11 18:19:14 +02:00
// Check struct..
unsigned int indentlevel2 = 0 ;
2015-06-03 17:17:53 +02:00
for ( const Token * tok2 = variable - > nameToken ( ) ; tok2 & & tok2 ! = variable - > scope ( ) - > classEnd ; tok2 = tok2 - > next ( ) ) {
2011-05-11 18:19:14 +02:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " } " ) {
2011-05-11 18:19:14 +02:00
if ( indentlevel2 = = 0 )
break ;
- - indentlevel2 ;
}
2009-07-19 16:51:31 +02:00
2011-05-11 18:19:14 +02:00
// Unknown usage of struct
/** @todo Check how the struct is used. Only bail out if necessary */
2013-07-20 12:31:04 +02:00
else if ( Token : : Match ( tok2 , " [(,] %varid% [,)] " , variable - > declarationId ( ) ) )
2011-05-11 18:19:14 +02:00
break ;
// Struct member is allocated => check if it is also properly deallocated..
2015-02-05 15:30:49 +01:00
else if ( Token : : Match ( tok2 - > previous ( ) , " [ ; { } ] % varid % . % var % = malloc | strdup | kmalloc | fopen ( " , variable->declarationId())
| | Token : : Match ( tok2 - > previous ( ) , " [;{}] %varid% . %var% = new " , variable - > declarationId ( ) ) ) {
2013-07-20 12:31:04 +02:00
const unsigned int structid ( variable - > declarationId ( ) ) ;
2011-05-11 18:19:14 +02:00
const unsigned int structmemberid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
// This struct member is allocated.. check that it is deallocated
unsigned int indentlevel3 = indentlevel2 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > next ( ) ) {
2011-05-11 18:19:14 +02:00
if ( tok3 - > str ( ) = = " { " )
+ + indentlevel3 ;
2011-10-13 20:53:06 +02:00
else if ( tok3 - > str ( ) = = " } " ) {
if ( indentlevel3 = = 0 ) {
2012-05-03 10:43:47 +02:00
memoryLeak ( tok3 , variable - > name ( ) + " . " + tok2 - > strAt ( 2 ) , Malloc ) ;
2009-07-19 16:51:31 +02:00
break ;
}
2011-05-11 18:19:14 +02:00
- - indentlevel3 ;
2009-07-19 16:51:31 +02:00
}
2011-05-11 18:19:14 +02:00
// Deallocating the struct member..
2013-04-26 16:11:57 +02:00
else if ( Token : : Match ( tok3 , " free|kfree ( %var% . %varid% ) " , structmemberid )
2013-04-30 06:44:50 +02:00
| | Token : : Match ( tok3 , " delete %var% . %varid% " , structmemberid )
| | Token : : Match ( tok3 , " delete [ ] %var% . %varid% " , structmemberid )
| | Token : : Match ( tok3 , " fclose ( %var% . %varid% " , structmemberid ) ) {
2011-05-11 18:19:14 +02:00
// If the deallocation happens at the base level, don't check this member anymore
if ( indentlevel3 = = 0 )
2009-07-19 16:51:31 +02:00
break ;
2011-05-11 18:19:14 +02:00
// deallocating and then returning from function in a conditional block =>
// skip ahead out of the block
bool ret = false ;
2011-10-13 20:53:06 +02:00
while ( tok3 ) {
2011-05-11 18:19:14 +02:00
if ( tok3 - > str ( ) = = " return " )
ret = true ;
else if ( tok3 - > str ( ) = = " { " || tok3->str() == " } " )
break ;
tok3 = tok3 - > next ( ) ;
}
if ( ! ret | | ! tok3 | | tok3 - > str ( ) ! = " } " )
break ;
- - indentlevel3 ;
continue ;
2009-07-19 16:51:31 +02:00
}
2011-05-11 18:19:14 +02:00
// Deallocating the struct..
2011-10-13 20:53:06 +02:00
else if ( indentlevel2 = = 0 & & Token : : Match ( tok3 , " free|kfree ( %varid% ) " , structid)) {
2012-05-03 10:43:47 +02:00
memoryLeak ( tok3 , variable - > name ( ) + " . " + tok2 - > strAt ( 2 ) , Malloc ) ;
2009-07-29 11:38:20 +02:00
break ;
2011-05-11 18:19:14 +02:00
}
2009-07-29 11:38:20 +02:00
2011-05-11 18:19:14 +02:00
// failed allocation => skip code..
2015-07-21 20:56:47 +02:00
else if ( Token : : simpleMatch ( tok3 , " if ( " ) & &
notvar ( tok3 - > next ( ) - > astOperand2 ( ) , structmemberid ) ) {
2011-05-11 18:19:14 +02:00
// Goto the ")"
tok3 = tok3 - > next ( ) - > link ( ) ;
2009-07-19 16:51:31 +02:00
2011-05-11 18:19:14 +02:00
// make sure we have ") {".. it should be
if ( ! Token : : simpleMatch ( tok3 , " ) { " ) )
break ;
2009-01-15 21:34:39 +01:00
2011-05-11 18:19:14 +02:00
// Goto the "}"
tok3 = tok3 - > next ( ) - > link ( ) ;
}
2009-07-19 16:51:31 +02:00
2011-05-11 18:19:14 +02:00
// succeeded allocation
2015-07-22 16:45:14 +02:00
else if ( ifvar ( tok3 , structmemberid , " != " , " 0 " ) ) {
2011-05-11 18:19:14 +02:00
// goto the ")"
tok3 = tok3 - > next ( ) - > link ( ) ;
2009-07-20 14:39:24 +02:00
2011-05-11 18:19:14 +02:00
// check if the variable is deallocated or returned..
unsigned int indentlevel4 = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) ) {
2011-05-11 18:19:14 +02:00
if ( tok4 - > str ( ) = = " { " )
+ + indentlevel4 ;
2011-10-13 20:53:06 +02:00
else if ( tok4 - > str ( ) = = " } " ) {
2011-05-11 18:19:14 +02:00
- - indentlevel4 ;
if ( indentlevel4 = = 0 )
2009-07-20 14:39:24 +02:00
break ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok4 , " free|kfree ( %var% . %varid% ) " , structmemberid)) {
2009-07-19 16:51:31 +02:00
break ;
}
2011-05-11 18:19:14 +02:00
}
2009-07-19 16:51:31 +02:00
2011-05-11 18:19:14 +02:00
// was there a proper deallocation?
if ( indentlevel4 > 0 )
break ;
}
2009-07-19 16:51:31 +02:00
2011-05-11 18:19:14 +02:00
// Returning from function..
2011-10-13 20:53:06 +02:00
else if ( tok3 - > str ( ) = = " return " ) {
2011-05-11 18:19:14 +02:00
// Returning from function without deallocating struct member?
if ( ! Token : : Match ( tok3 , " return %varid% ; " , structid ) & &
2011-10-13 20:53:06 +02:00
! Token : : Match ( tok3 , " return & %varid% . " , structid ) ) {
2012-05-03 10:43:47 +02:00
memoryLeak ( tok3 , variable - > name ( ) + " . " + tok2 - > strAt ( 2 ) , Malloc ) ;
2011-05-11 18:19:14 +02:00
}
break ;
}
2009-08-17 22:23:37 +02:00
2011-08-08 19:58:25 +02:00
// struct assignment..
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok3 , " = %varid% ; " , structid ) ) {
2011-08-08 19:58:25 +02:00
break ;
2012-06-23 20:15:58 +02:00
} else if ( Token : : Match ( tok3 , " = %var% . %varid% ; " , structmemberid ) ) {
break ;
2011-08-08 19:58:25 +02:00
}
2011-05-11 18:19:14 +02:00
// goto isn't handled well.. bail out even though there might be leaks
else if ( tok3 - > str ( ) = = " goto " )
break ;
2009-07-19 16:51:31 +02:00
2011-05-11 18:19:14 +02:00
// using struct in a function call..
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok3 , " %name% ( " ) ) {
2011-05-11 18:19:14 +02:00
// Calling non-function / function that doesn't deallocate?
if ( ignoredFunctions . find ( tok3 - > str ( ) ) ! = ignoredFunctions . end ( ) )
continue ;
2009-09-28 22:41:45 +02:00
2011-05-11 18:19:14 +02:00
// Check if the struct is used..
bool deallocated = false ;
2012-04-21 23:05:37 +02:00
const Token * const end4 = tok3 - > linkAt ( 1 ) ;
for ( const Token * tok4 = tok3 ; tok4 ! = end4 ; tok4 = tok4 - > next ( ) ) {
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok4 , " [(,] &| %varid% [,)] " , structid ) ) {
2011-05-11 18:19:14 +02:00
/** @todo check if the function deallocates the memory */
deallocated = true ;
2009-07-19 16:51:31 +02:00
break ;
}
2011-08-20 09:17:34 +02:00
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok4 , " [(,] &| %varid% . %name% [,)] " , structid ) ) {
2011-08-20 09:17:34 +02:00
/** @todo check if the function deallocates the memory */
deallocated = true ;
break ;
}
2009-07-19 16:51:31 +02:00
}
2011-05-11 18:19:14 +02:00
if ( deallocated )
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
2010-11-12 21:09:34 +01:00
void CheckMemoryLeakNoVar : : check ( )
{
2011-01-16 18:13:54 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-12-09 06:15:01 +01:00
2012-10-21 09:07:51 +02:00
// only check functions
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2010-11-12 21:09:34 +01:00
2014-01-03 10:12:32 +01:00
// Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
checkForUnusedReturnValue ( scope ) ;
2015-01-04 11:07:53 +01:00
// Checks to see if a function is called with memory allocated for an argument that
// could be leaked if a function called for another argument throws.
checkForUnsafeArgAlloc ( scope ) ;
2010-11-12 21:09:34 +01:00
// goto the "}" that ends the executable scope..
2011-01-17 18:29:19 +01:00
const Token * tok = scope - > classEnd ;
2010-11-12 21:09:34 +01:00
// parse the executable scope until tok is reached...
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > link ( ) ; tok2 & & tok2 ! = tok ; tok2 = tok2 - > next ( ) ) {
2010-11-12 21:09:34 +01:00
// allocating memory in parameter for function call..
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 , " [(,] %name% ( " ) & & Token : : Match ( tok2 - > linkAt ( 2 ) , " ) [,)] " ) ) {
2010-11-12 21:09:34 +01:00
const AllocType allocType = getAllocationType ( tok2 - > next ( ) , 0 ) ;
2011-10-13 20:53:06 +02:00
if ( allocType ! = No ) {
2010-11-12 21:09:34 +01:00
// locate outer function call..
2011-10-13 20:53:06 +02:00
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > previous ( ) ) {
if ( tok3 - > str ( ) = = " ( " ) {
2010-11-12 21:09:34 +01:00
// Is it a function call..
2015-01-31 10:50:39 +01:00
if ( ! Token : : Match ( tok3 - > tokAt ( - 2 ) , " = %name% ( " ) ) {
2012-05-25 12:09:41 +02:00
const std : : string & functionName = tok3 - > strAt ( - 1 ) ;
2015-01-30 20:55:53 +01:00
if ( ( tokenizer - > isCPP ( ) & & functionName = = " delete " ) | |
2011-01-02 08:32:51 +01:00
functionName = = " free " | |
functionName = = " fclose " | |
functionName = = " realloc " )
break ;
2015-01-30 20:55:53 +01:00
if ( CheckMemoryLeakInFunction : : test_white_list ( functionName , _settings , tokenizer - > isCPP ( ) ) ) {
2010-11-12 21:09:34 +01:00
functionCallLeak ( tok2 , tok2 - > strAt ( 1 ) , functionName ) ;
break ;
}
}
break ;
2011-10-13 20:53:06 +02:00
} else if ( tok3 - > str ( ) = = " ) " )
2010-11-12 21:09:34 +01:00
tok3 = tok3 - > link ( ) ;
else if ( Token : : Match ( tok3 , " [;{}] " ) )
break ;
}
}
}
}
}
}
2014-01-03 10:12:32 +01:00
//---------------------------------------------------------------------------
// Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
//---------------------------------------------------------------------------
void CheckMemoryLeakNoVar : : checkForUnusedReturnValue ( const Scope * scope )
{
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2015-06-19 23:44:43 +02:00
if ( ! tok - > varId ( ) & & Token : : Match ( tok , " %name% ( " ) & & ( ! tok - > next ( ) - > astParent ( ) | | tok - > next ( ) - > astParent ( ) - > str ( ) = = " ! " | | tok - > next ( ) - > astParent ( ) - > isComparisonOp ( ) ) & & tok - > next ( ) - > astOperand1 ( ) = = tok ) {
2015-01-31 17:27:43 +01:00
const AllocType allocType = getAllocationType ( tok , 0 ) ;
if ( allocType ! = No )
2014-01-03 10:12:32 +01:00
returnValueNotUsedError ( tok , tok - > str ( ) ) ;
}
}
}
2015-01-04 11:07:53 +01:00
//---------------------------------------------------------------------------
// Check if an exception could cause a leak in an argument constructed with
// shared_ptr/unique_ptr. For example, in the following code, it is possible
// that if g() throws an exception, the memory allocated by "new int(42)"
// could be leaked. See stackoverflow.com/questions/19034538/
// why-is-there-memory-leak-while-using-shared-ptr-as-a-function-parameter
//
// void x() {
// f(shared_ptr<int>(new int(42)), g());
// }
//---------------------------------------------------------------------------
void CheckMemoryLeakNoVar : : checkForUnsafeArgAlloc ( const Scope * scope )
{
// This test only applies to C++ source
if ( ! _tokenizer - > isCPP ( ) | | ! _settings - > inconclusive | | ! _settings - > isEnabled ( " warning " ) )
return ;
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% ( " ) ) {
2015-01-04 11:07:53 +01:00
const Token * endParamToken = tok - > next ( ) - > link ( ) ;
std : : string pointerType ;
std : : string objectType ;
std : : string functionCalled ;
// Scan through the arguments to the function call
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 & & tok2 ! = endParamToken ; tok2 = tok2 - > nextArgument ( ) ) {
2015-02-27 10:02:12 +01:00
const Function * func = tok2 - > function ( ) ;
const bool isNothrow = func & & ( func - > isAttributeNothrow ( ) | | func - > isThrow ( ) ) ;
2015-01-04 11:07:53 +01:00
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 , " shared_ptr|unique_ptr < %name% > ( new %name% " ) ) {
2015-01-04 11:07:53 +01:00
pointerType = tok2 - > str ( ) ;
objectType = tok2 - > strAt ( 6 ) ;
} else if ( ! isNothrow ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 , " %name% ( " ) )
2015-01-04 11:07:53 +01:00
functionCalled = tok2 - > str ( ) ;
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok2 , " %name% < %name% > ( " ) )
2015-01-04 11:07:53 +01:00
functionCalled = tok2 - > str ( ) + " < " + tok2 - > strAt ( 2 ) + " > " ;
}
}
if ( ! pointerType . empty ( ) & & ! functionCalled . empty ( ) )
unsafeArgAllocError ( tok , functionCalled , pointerType , objectType ) ;
}
}
}
2010-11-12 21:09:34 +01:00
void CheckMemoryLeakNoVar : : functionCallLeak ( const Token * loc , const std : : string & alloc , const std : : string & functionCall )
{
reportError ( loc , Severity : : error , " leakNoVarFunctionCall " , " Allocation with " + alloc + " , " + functionCall + " doesn't release it. " ) ;
}
2014-01-03 10:12:32 +01:00
void CheckMemoryLeakNoVar : : returnValueNotUsedError ( const Token * tok , const std : : string & alloc )
{
2015-07-31 13:52:21 +02:00
reportError ( tok , Severity : : error , " leakReturnValNotUsed " , " Return value of allocation function ' " + alloc + " ' is not stored. " ) ;
2014-01-03 10:12:32 +01:00
}
2015-01-04 11:07:53 +01:00
void CheckMemoryLeakNoVar : : unsafeArgAllocError ( const Token * tok , const std : : string & funcName , const std : : string & ptrType , const std : : string & objType )
{
const std : : string factoryFunc = ptrType = = " shared_ptr " ? " make_shared " : " make_unique " ;
reportError ( tok , Severity : : warning , " leakUnsafeArgAlloc " ,
" Unsafe allocation. If " + funcName + " () throws, memory could be leaked. Use " + factoryFunc + " < " + objType + " >() instead. " ,
2015-04-25 17:48:11 +02:00
0U ,
2015-01-04 11:07:53 +01:00
true ) ; // Inconclusive because funcName may never throw
}