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
2011-01-09 20:33:36 +01:00
* Copyright ( C ) 2007 - 2011 Daniel Marjamäki and Cppcheck team .
2009-01-15 21:34:39 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-15 21:34:39 +01:00
*/
# include "checkmemoryleak.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2009-03-20 18:16:21 +01:00
# include "tokenize.h"
2009-12-14 20:30:31 +01:00
# include "executionpath.h"
2009-03-20 18:16:21 +01:00
2009-01-15 21:34:39 +01:00
# include <algorithm>
2009-01-23 21:55:06 +01:00
# include <cstring>
2009-08-22 20:23:03 +02:00
# include <cstdlib>
2009-01-15 21:34:39 +01:00
# include <iostream>
# include <sstream>
2009-07-22 08:30:51 +02:00
# include <set>
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)
namespace
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
CheckMemoryLeakInFunction instance1 ;
CheckMemoryLeakInClass instance2 ;
2009-07-19 16:51:31 +02:00
CheckMemoryLeakStructMember instance3 ;
2010-11-12 21:09:34 +01:00
CheckMemoryLeakNoVar instance4 ;
2009-01-15 21:34:39 +01:00
}
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 .
* This list contains function names whith const parameters e . g . : atof ( const char * )
* Reference : http : //www.aquaphoenix.com/ref/gnu_c_library/libc_492.html#SEC492
*/
2009-08-22 20:23:03 +02:00
static const char * const call_func_white_list [ ] =
{
2011-03-22 22:13:29 +01:00
" _open " , " _wopen " , " access " , " adjtime " , " asctime " , " asctime_r " , " asprintf " , " assert "
2011-03-21 23:20:46 +01:00
, " atof " , " atoi " , " atol " , " chdir " , " chmod " , " chown "
2011-03-22 22:13:29 +01:00
, " clearerr " , " creat " , " ctime " , " ctime_r " , " delete " , " execl " , " execle "
, " execlp " , " execv " , " execve " , " fchmod " , " fclose " , " fcntl "
2011-06-20 18:42:13 +02:00
, " fdatasync " , " feof " , " ferror " , " fflush " , " fgetc " , " fgetpos " , " fgets "
2011-03-22 22:13:29 +01:00
, " 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 "
, " obstack_printf " , " obstack_vprintf " , " open " , " opendir " , " parse_printf_format " , " pathconf "
, " perror " , " popen " , " posix_fadvise " , " posix_fallocate " , " pread "
, " printf " , " psignal " , " putenv " , " puts " , " pwrite " , " qsort " , " read " , " readahead " , " readdir " , " readdir_r "
, " readlink " , " readv "
2011-03-23 00:20:05 +01:00
, " realloc " , " regcomp " , " remove " , " rename " , " return " , " rewind " , " rewinddir " , " rindex "
2011-03-22 22:13:29 +01:00
, " rmdir " , " scandir " , " scanf " , " seekdir "
2011-04-19 16:55:27 +02:00
, " setbuf " , " setbuffer " , " sethostname " , " setlinebuf " , " setlocale " , " setvbuf " , " sizeof " , " snprintf " , " sprintf " , " sscanf "
2011-03-21 23:59:43 +01:00
, " stat " , " stpcpy " , " strcasecmp " , " strcat " , " strchr " , " strcmp " , " strcoll "
, " strcpy " , " strcspn " , " strdup " , " stricmp " , " strlen " , " strncasecmp " , " strncat " , " strncmp "
2011-09-09 07:25:47 +02:00
, " strncpy " , " strpbrk " , " strrchr " , " strspn " , " strstr " , " strtod " , " strtok " , " strtol " , " strtoul " , " strxfrm " , " switch "
2011-03-22 22:13:29 +01:00
, " 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
} ;
static int call_func_white_list_compare ( const void * a , const void * b )
{
return strcmp ( ( const char * ) a , * ( const char * * ) b ) ;
}
2009-03-20 18:16:21 +01:00
//---------------------------------------------------------------------------
2009-01-15 21:34:39 +01:00
2011-07-15 02:45:27 +02:00
bool CheckMemoryLeak : : isclass ( const Tokenizer * _tokenizer , 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 ;
2011-07-15 02:45:27 +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 */
if ( var & & var - > type ( ) & & var - > type ( ) - > numConstructors = = 0 & &
( var - > type ( ) - > varlist . empty ( ) | | var - > type ( ) - > needInitialization = = Scope : : True ) & &
var - > type ( ) - > derivedFrom . empty ( ) )
return false ;
2009-01-15 21:34:39 +01:00
return true ;
}
//---------------------------------------------------------------------------
2011-03-23 18:45:47 +01:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getAllocationType ( const Token * tok2 , unsigned int varid , std : : list < const Token * > * 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);
2010-04-02 07:30:58 +02:00
if ( tok2 & & tok2 - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
{
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 ? tok2 - > next ( ) : NULL ;
}
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-01-15 21:34:39 +01:00
return No ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 - > isName ( ) )
2009-01-15 21:34:39 +01:00
return No ;
// Does tok2 point on "malloc", "strdup" or "kmalloc"..
2009-05-21 12:26:44 +02:00
static const char * const mallocfunc [ ] = { " malloc " ,
" calloc " ,
" strdup " ,
" strndup " ,
" kmalloc " ,
" kzalloc " ,
" kcalloc " ,
0
} ;
2010-04-02 07:30:58 +02:00
for ( unsigned int i = 0 ; mallocfunc [ i ] ; i + + )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = mallocfunc [ i ] )
2009-01-15 21:34:39 +01:00
return Malloc ;
}
2009-08-10 22:04:28 +02:00
// Using realloc..
2010-04-02 07:30:58 +02:00
if ( varid & & Token : : Match ( tok2 , " realloc ( %any% , " ) & & tok2 - > tokAt ( 2 ) - > varId ( ) ! = varid )
2009-08-10 22:04:28 +02:00
return Malloc ;
2009-01-15 21:34:39 +01:00
// Does tok2 point on "g_malloc", "g_strdup", ..
2009-05-21 12:26:44 +02:00
static const char * const gmallocfunc [ ] = { " g_new " ,
" g_new0 " ,
" g_try_new " ,
" g_try_new0 " ,
" g_malloc " ,
" g_malloc0 " ,
" g_try_malloc " ,
" g_try_malloc0 " ,
" g_strdup " ,
" g_strndup " ,
2010-06-06 11:09:19 +02:00
" g_strdup_printf " ,
2009-05-21 12:26:44 +02:00
0
} ;
2010-04-02 07:30:58 +02:00
for ( unsigned int i = 0 ; gmallocfunc [ i ] ; i + + )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = gmallocfunc [ i ] )
2009-01-15 21:34:39 +01:00
return gMalloc ;
}
2011-08-07 01:10:15 +02:00
if ( Token : : Match ( tok2 , " new struct| %type% [;()] " ) | |
Token : : Match ( tok2 , " new ( std :: nothrow ) struct| %type% [;()] " ) | |
Token : : Match ( tok2 , " new ( nothrow ) struct| %type% [;()] " ) )
2009-01-15 21:34:39 +01:00
return New ;
2011-08-07 01:10:15 +02:00
if ( Token : : Match ( tok2 , " new struct| %type% [ " ) | |
Token : : Match ( tok2 , " new ( std :: nothrow ) struct| %type% [ " ) | |
Token : : Match ( tok2 , " new ( nothrow ) struct| %type% [ " ) )
2009-01-31 14:57:27 +01:00
return NewArray ;
2009-01-15 21:34:39 +01:00
2010-05-29 21:56:18 +02:00
if ( Token : : Match ( tok2 , " fopen|tmpfile|g_fopen ( " ) )
2009-05-21 12:16:42 +02:00
return File ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " open|openat|creat|mkstemp|mkostemp ( " ) )
2010-01-26 20:10:52 +01:00
{
// is there a user function with this name?
2010-04-02 07:30:58 +02:00
if ( tokenizer & & Token : : findmatch ( tokenizer - > tokens ( ) , ( " %type% *|&| " + tok2 - > str ( ) ) . c_str ( ) ) )
2010-01-26 20:10:52 +01:00
return No ;
2009-06-21 17:01:43 +02:00
return Fd ;
2010-01-26 20:10:52 +01:00
}
2009-06-21 17:01:43 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " popen ( " ) )
2009-05-21 12:16:42 +02:00
return Pipe ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " opendir|fdopendir ( " ) )
2009-05-22 09:24:03 +02:00
return Dir ;
2011-03-19 14:05:22 +01:00
// User function
const Token * ftok = tokenizer - > getFunctionTokenByName ( tok2 - > str ( ) . c_str ( ) ) ;
2011-03-23 18:45:47 +01:00
if ( ftok = = NULL )
return No ;
// Prevent recursion
if ( callstack & & std : : find ( callstack - > begin ( ) , callstack - > end ( ) , ftok ) ! = callstack - > end ( ) )
return No ;
std : : list < const Token * > cs ;
if ( ! callstack )
callstack = & cs ;
callstack - > push_back ( ftok ) ;
return functionReturnType ( ftok , callstack ) ;
2009-01-15 21:34:39 +01:00
}
2009-08-19 19:42:07 +02:00
2009-08-25 21:25:27 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getReallocationType ( const Token * tok2 , unsigned int varid ) const
2009-01-15 21:34:39 +01:00
{
// What we may have...
// * var = (char *)realloc(..;
2010-04-02 07:30:58 +02:00
if ( tok2 & & tok2 - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
{
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 ? tok2 - > next ( ) : NULL ;
}
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-01-15 21:34:39 +01:00
return No ;
2010-05-10 18:11:02 +02:00
if ( varid > 0 & & ! Token : : Match ( tok2 , " %var% ( %varid% [,)] " , varid ) )
2009-08-18 20:49:08 +02:00
return No ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " realloc " )
2009-01-15 21:34:39 +01:00
return Malloc ;
// GTK memory reallocation..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " g_realloc|g_try_realloc|g_renew|g_try_renew " ) )
2009-01-15 21:34:39 +01:00
return gMalloc ;
return No ;
}
2009-08-25 21:25:27 +02:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : getDeallocationType ( const Token * tok , unsigned int varid ) const
2009-08-19 19:42:07 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete %varid% ; " , varid ) )
2009-08-19 19:42:07 +02:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete [ ] %varid% ; " , varid ) )
2009-08-19 19:42:07 +02:00
return NewArray ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete ( %varid% ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return New ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " delete [ ] ( %varid% ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return NewArray ;
2010-11-20 08:35:23 +01:00
if ( Token : : Match ( tok , " free|kfree ( %varid% ) ; " , varid ) | |
2011-08-31 05:42:11 +02:00
Token : : Match ( tok , " free|kfree ( %varid% - " , varid ) | |
Token : : Match ( tok , " realloc ( %varid% , 0 ) ; " , varid ) )
2009-08-19 19:42:07 +02:00
return Malloc ;
2010-11-20 08:35:23 +01:00
if ( Token : : Match ( tok , " g_free ( %varid% ) ; " , varid ) | |
Token : : Match ( tok , " g_free ( %varid% - " , varid ) )
2009-08-19 19:42:07 +02:00
return gMalloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " fclose ( %varid% ) " , varid ) | |
2011-02-02 16:48:00 +01:00
Token : : simpleMatch ( tok , " fcloseall ( ) " ) )
2009-08-19 19:42:07 +02:00
return File ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " close ( %varid% ) " , varid ) )
2009-08-19 19:42:07 +02:00
return Fd ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " pclose ( %varid% ) " , varid ) )
2009-08-19 19:42:07 +02:00
return Pipe ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " closedir ( %varid% ) " , varid ) )
2009-08-19 19:42:07 +02:00
return Dir ;
return No ;
}
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
{
2011-08-16 20:39:17 +02:00
if ( Token : : Match ( tok , std : : string ( " delete " + varname + " [,;] " ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return New ;
2011-08-16 20:39:17 +02:00
if ( Token : : Match ( tok , std : : string ( " delete [ ] " + varname + " [,;] " ) . c_str ( ) ) )
2009-01-31 14:57:27 +01:00
return NewArray ;
2009-01-15 21:34:39 +01:00
2011-08-16 20:39:17 +02:00
if ( Token : : Match ( tok , std : : string ( " delete ( " + varname + " ) [,;] " ) . c_str ( ) ) )
2009-02-14 07:54:23 +01:00
return New ;
2011-08-16 20:39:17 +02:00
if ( Token : : Match ( tok , std : : string ( " delete [ ] ( " + varname + " ) [,;] " ) . c_str ( ) ) )
2009-02-14 07:54:23 +01:00
return NewArray ;
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 ( " g_free ( " + varname + " ) ; " ) . c_str ( ) ) )
2009-01-15 21:34:39 +01:00
return gMalloc ;
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
2010-12-07 07:07:36 +01:00
if ( Token : : simpleMatch ( tok , std : : string ( " closedir ( " + varname + " ) " ) . c_str ( ) ) )
2009-05-22 09:24:03 +02:00
return Dir ;
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
//--------------------------------------------------------------------------
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : memoryLeak ( const Token * tok , const std : : string & varname , AllocType alloctype )
2009-06-08 20:20:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( alloctype = = CheckMemoryLeak : : File | |
alloctype = = CheckMemoryLeak : : Pipe | |
alloctype = = CheckMemoryLeak : : Fd | |
alloctype = = CheckMemoryLeak : : Dir )
2010-05-16 19:55:16 +02:00
resourceLeakError ( tok , varname . c_str ( ) ) ;
2009-06-08 20:20:43 +02:00
else
2010-05-16 19:55:16 +02:00
memleakError ( tok , varname . c_str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
//---------------------------------------------------------------------------
2010-07-14 16:30:03 +02:00
void CheckMemoryLeak : : reportErr ( const Token * tok , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg ) const
2009-07-13 15:07:26 +02:00
{
2009-08-04 21:36:55 +02:00
std : : list < const Token * > callstack ;
2009-07-13 15:07:26 +02:00
2010-04-02 07:30:58 +02:00
if ( tok )
2009-08-04 21:36:55 +02:00
callstack . push_back ( tok ) ;
2009-07-13 15:07:26 +02:00
2009-08-04 21:36:55 +02:00
reportErr ( callstack , severity , id , msg ) ;
2009-07-13 15:07:26 +02:00
}
2010-07-14 16:30:03 +02:00
void CheckMemoryLeak : : reportErr ( const std : : list < const Token * > & callstack , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg ) const
2009-07-13 15:07:26 +02:00
{
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > locations ;
2009-06-08 20:20:43 +02:00
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = callstack . begin ( ) ; it ! = callstack . end ( ) ; + + it )
2009-07-13 15:07:26 +02:00
{
2009-12-22 21:56:00 +01:00
const Token * const tok = * it ;
2009-07-13 15:07:26 +02:00
ErrorLogger : : ErrorMessage : : FileLocation loc ;
2009-12-22 21:56:00 +01:00
loc . line = tok - > linenr ( ) ;
2010-07-17 00:27:40 +02:00
loc . setfile ( tokenizer - > file ( tok ) ) ;
2009-07-13 15:07:26 +02:00
locations . push_back ( loc ) ;
}
2011-04-14 18:02:01 +02:00
const ErrorLogger : : ErrorMessage errmsg ( locations , severity , msg , id , false ) ;
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
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : memleakError ( const Token * tok , const std : : string & varname )
2009-06-08 20:20:43 +02:00
{
2010-05-16 19:55:16 +02:00
reportErr ( tok , Severity : : error , " memleak " , " Memory leak: " + varname ) ;
2009-06-08 20:20:43 +02:00
}
2010-05-18 07:46:48 +02:00
void CheckMemoryLeak : : memleakUponReallocFailureError ( const Token * tok , const std : : string & varname )
{
2011-01-08 14:35:09 +01:00
reportErr ( tok , Severity : : error , " memleakOnRealloc " , " Common realloc mistake: \' " + varname + " \' nulled but not freed upon failure " ) ;
2010-05-18 07:46:48 +02:00
}
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : resourceLeakError ( const Token * tok , const std : : string & varname )
2009-06-08 20:20:43 +02:00
{
2009-10-03 21:46:22 +02:00
std : : string errmsg ( " Resource leak " ) ;
2010-04-02 07:30:58 +02:00
if ( ! varname . empty ( ) )
2009-10-03 21:46:22 +02:00
errmsg + = " : " + varname ;
2010-05-16 19:55:16 +02:00
reportErr ( tok , Severity : : error , " resourceLeak " , errmsg ) ;
2009-06-08 20:20:43 +02:00
}
void CheckMemoryLeak : : deallocDeallocError ( const Token * tok , const std : : string & varname )
{
2009-08-04 21:36:55 +02:00
reportErr ( tok , Severity : : error , " deallocDealloc " , " Deallocating a deallocated pointer: " + varname ) ;
2009-06-08 20:20:43 +02:00
}
void CheckMemoryLeak : : deallocuseError ( const Token * tok , const std : : string & varname )
{
2009-08-04 21:36:55 +02:00
reportErr ( tok , Severity : : error , " deallocuse " , " Dereferencing ' " + varname + " ' after it is deallocated / released " ) ;
2009-06-08 20:20:43 +02:00
}
void CheckMemoryLeak : : mismatchSizeError ( const Token * tok , const std : : string & sz )
{
2009-08-04 21:36:55 +02:00
reportErr ( tok , Severity : : error , " mismatchSize " , " The given size " + sz + " is mismatching " ) ;
2009-06-08 20:20:43 +02:00
}
2010-05-16 19:55:16 +02:00
void CheckMemoryLeak : : mismatchAllocDealloc ( const std : : list < const Token * > & callstack , const std : : string & varname )
2009-06-08 20:20:43 +02:00
{
2010-05-16 19:55:16 +02:00
reportErr ( callstack , Severity : : error , " mismatchAllocDealloc " , " Mismatching allocation and deallocation: " + varname ) ;
2009-06-08 20:20:43 +02:00
}
2011-03-23 18:45:47 +01:00
CheckMemoryLeak : : AllocType CheckMemoryLeak : : functionReturnType ( const Token * tok , std : : list < const Token * > * callstack ) const
2009-06-15 17:44:59 +02:00
{
2011-03-20 09:16:52 +01:00
if ( ! tok )
return No ;
// Locate start of function
2010-04-02 07:30:58 +02:00
while ( tok )
2009-06-15 17:44:59 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " | | tok - > str ( ) = = " } " )
2009-06-15 17:44:59 +02:00
return No ;
2009-06-08 20:20:43 +02:00
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-06-15 17:44:59 +02:00
{
2011-03-20 09:16:52 +01:00
tok = tok - > link ( ) ;
2009-06-15 17:44:59 +02:00
break ;
}
tok = tok - > next ( ) ;
}
2009-06-15 21:13:39 +02:00
// Is this the start of a function?
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " ) const| { " ) )
2009-06-15 21:13:39 +02:00
return No ;
2010-04-02 07:30:58 +02:00
while ( tok - > str ( ) ! = " { " )
2009-06-15 21:13:39 +02:00
tok = tok - > next ( ) ;
2010-05-09 13:46:13 +02:00
// Get return pointer..
2009-08-19 19:42:07 +02:00
unsigned int varid = 0 ;
2010-05-09 13:46:13 +02:00
unsigned int indentlevel = 0 ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
if ( indentlevel < = 1 )
return No ;
2010-05-30 20:30:08 +02:00
- - indentlevel ;
2009-06-15 21:13:39 +02:00
}
2010-05-09 13:46:13 +02:00
if ( Token : : Match ( tok2 , " return %var% ; " ) )
2009-06-15 21:13:39 +02:00
{
2010-05-09 13:46:13 +02:00
if ( indentlevel ! = 1 )
2009-06-15 21:13:39 +02:00
return No ;
2010-05-09 13:46:13 +02:00
varid = tok2 - > next ( ) - > varId ( ) ;
break ;
2009-06-15 21:13:39 +02:00
}
2010-05-09 13:46:13 +02:00
else if ( tok2 - > str ( ) = = " return " )
2010-04-24 20:40:57 +02:00
{
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 ;
// Check if return pointer is allocated..
AllocType allocType = No ;
while ( 0 ! = ( tok = tok - > next ( ) ) )
{
if ( Token : : Match ( tok , " %varid% = " , varid ) )
2009-06-15 21:13:39 +02:00
{
2011-03-23 18:45:47 +01:00
allocType = getAllocationType ( tok - > tokAt ( 2 ) , varid , callstack ) ;
2010-12-29 22:18:23 +01:00
}
if ( Token : : Match ( tok , " = %varid% ; " , varid ) )
{
return No ;
2009-06-15 21:13:39 +02:00
}
2011-07-24 16:08:29 +02:00
if ( Token : : Match ( tok , " static %type% * %varid% [;{}=] " , varid ) )
{
return No ;
}
2011-03-24 17:14:12 +01:00
if ( Token : : Match ( tok , " [(,] %varid% [,)] " , varid ) )
{
return No ;
}
2010-05-09 13:46:13 +02:00
if ( tok - > str ( ) = = " return " )
return allocType ;
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
2010-06-17 03:29:55 +02:00
const char * CheckMemoryLeak : : functionArgAlloc ( const Token * tok , unsigned int targetpar , AllocType & allocType ) const
2010-06-05 01:58:50 +02:00
{
// Find the varid of targetpar, then locate the start of the function..
unsigned int parlevel = 0 ;
unsigned int par = 0 ;
unsigned int varid = 0 ;
2010-06-17 03:29:55 +02:00
allocType = No ;
2010-06-05 01:58:50 +02:00
while ( tok )
{
if ( tok - > str ( ) = = " { " | | tok - > str ( ) = = " } " )
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
if ( tok - > str ( ) = = " ( " )
{
if ( parlevel ! = 0 )
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
+ + parlevel ;
+ + par ;
}
else if ( tok - > str ( ) = = " ) " )
{
if ( parlevel ! = 1 )
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
break ;
}
else if ( parlevel = = 1 & & tok - > str ( ) = = " , " )
{
+ + par ;
}
tok = tok - > next ( ) ;
if ( parlevel = = 1 & & par = = targetpar & & Token : : Match ( tok , " %type% * * %var% " ) )
{
varid = tok - > tokAt ( 3 ) - > varId ( ) ;
}
}
if ( varid = = 0 )
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
// Is this the start of a function?
if ( ! Token : : Match ( tok , " ) const| { " ) )
2010-06-17 03:29:55 +02:00
return " " ;
2010-06-05 01:58:50 +02:00
while ( tok - > str ( ) ! = " { " )
tok = tok - > next ( ) ;
// Check if pointer is allocated.
2010-06-17 03:29:55 +02:00
unsigned int indentlevel = 0 ;
int realloc = 0 ;
2010-06-05 01:58:50 +02:00
while ( 0 ! = ( tok = tok - > next ( ) ) )
{
2010-06-17 03:29:55 +02:00
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
{
if ( indentlevel < = 1 )
break ;
- - indentlevel ;
}
2010-07-06 21:36:50 +02:00
else if ( tok - > varId ( ) = = varid )
2010-06-17 03:29:55 +02:00
{
2010-07-06 21:36:50 +02:00
if ( Token : : Match ( tok - > tokAt ( - 3 ) , " free ( * %varid% ) " , varid ) )
2010-06-05 01:58:50 +02:00
{
2010-07-06 21:36:50 +02:00
realloc = 1 ;
allocType = No ;
2010-06-05 01:58:50 +02:00
}
2010-07-06 21:36:50 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " * %varid% = " , varid ) )
2010-06-05 01:58:50 +02:00
{
2010-07-06 21:36:50 +02:00
allocType = getAllocationType ( tok - > tokAt ( 2 ) , varid ) ;
if ( allocType = = No )
{
allocType = getReallocationType ( tok - > tokAt ( 2 ) , varid ) ;
}
if ( allocType ! = No )
{
if ( realloc )
return " realloc " ;
return " alloc " ;
}
}
else
{
// 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
}
2009-11-14 09:06:28 +01:00
void CheckMemoryLeakInFunction : : parse_noreturn ( )
{
2009-11-15 09:53:38 +01:00
noreturn . insert ( " exit " ) ;
noreturn . insert ( " _exit " ) ;
noreturn . insert ( " _Exit " ) ;
noreturn . insert ( " abort " ) ;
noreturn . insert ( " err " ) ;
noreturn . insert ( " verr " ) ;
noreturn . insert ( " errx " ) ;
noreturn . insert ( " verrx " ) ;
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-08 07:49:01 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2009-11-14 09:06:28 +01:00
{
2010-12-08 07:49:01 +01:00
// only check functions
2011-01-17 18:29:19 +01:00
if ( scope - > type ! = Scope : : eFunction )
2010-12-08 07:49:01 +01:00
continue ;
2009-11-14 09:06:28 +01:00
2010-12-08 07:49:01 +01:00
// parse this function to check if it contains an "exit" call..
unsigned int indentlevel = 1 ;
2011-01-17 18:29:19 +01:00
for ( const Token * tok2 = scope - > classStart - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2010-12-08 07:49:01 +01:00
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
2009-11-14 09:06:28 +01:00
{
2010-12-08 07:49:01 +01:00
- - indentlevel ;
if ( indentlevel = = 0 )
break ;
}
2011-01-11 20:14:15 +01:00
if ( Token : : Match ( tok2 - > previous ( ) , " [;{}] exit ( " ) )
2010-12-08 07:49:01 +01:00
{
2011-01-17 18:29:19 +01:00
noreturn . insert ( scope - > className ) ;
2010-12-08 07:49:01 +01:00
break ;
2009-11-14 09:06:28 +01:00
}
}
2011-01-11 20:14:15 +01:00
// This function is not a noreturn function
if ( indentlevel = = 0 )
{
2011-01-17 18:29:19 +01:00
notnoreturn . insert ( scope - > className ) ;
2011-01-11 20:14:15 +01:00
}
2009-11-14 09:06:28 +01:00
}
}
2009-08-25 21:25:27 +02:00
bool CheckMemoryLeakInFunction : : notvar ( const Token * tok , unsigned int varid , bool endpar ) const
2009-06-08 20:20:43 +02:00
{
const std : : string end ( endpar ? " &&|) " : " [;)&|] " ) ;
2009-08-19 19:42:07 +02:00
return bool ( Token : : Match ( tok , ( " ! %varid% " + end ) . c_str ( ) , varid ) | |
Token : : Match ( tok , ( " ! ( %varid% ) " + end ) . c_str ( ) , varid ) ) ;
2009-06-08 20:20:43 +02:00
}
2009-06-12 17:31:29 +02:00
static int countParameters ( const Token * tok )
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " %var% ( " ) )
2009-06-12 17:31:29 +02:00
return - 1 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " void| ) " ) )
2009-06-12 17:31:29 +02:00
return 0 ;
int numpar = 1 ;
int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-06-12 17:31:29 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-06-12 17:31:29 +02:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-06-12 17:31:29 +02:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel < = 1 )
2009-06-12 17:31:29 +02:00
return numpar ;
- - parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( parlevel = = 1 & & tok - > str ( ) = = " , " )
2010-05-30 20:30:08 +02:00
{
2009-06-12 17:31:29 +02:00
+ + numpar ;
2010-05-30 20:30:08 +02:00
}
2009-06-12 17:31:29 +02:00
}
return - 1 ;
}
2009-06-08 20:20:43 +02:00
2010-02-14 19:58:17 +01:00
bool CheckMemoryLeakInFunction : : test_white_list ( const std : : string & funcname )
2010-01-18 21:34:11 +01:00
{
2010-04-06 20:35:21 +02:00
return ( std : : bsearch ( funcname . c_str ( ) , call_func_white_list ,
sizeof ( call_func_white_list ) / sizeof ( call_func_white_list [ 0 ] ) ,
sizeof ( call_func_white_list [ 0 ] ) , call_func_white_list_compare ) ! = NULL ) ;
2010-01-18 21:34:11 +01:00
}
2010-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
{
2010-04-02 07:30:58 +02:00
if ( test_white_list ( tok - > str ( ) ) )
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 " | |
tok - > str ( ) = = " while " )
{
return 0 ;
}
2010-10-26 17:49:48 +02:00
// is the varid a parameter?
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " | | tok2 - > str ( ) = = " ) " )
break ;
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 " ;
else
return " use_ " ;
}
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
2011-01-01 20:14:01 +01:00
if ( noreturn . find ( tok - > str ( ) ) ! = noreturn . end ( ) & & tok - > strAt ( - 1 ) ! = " = " )
2009-11-14 09:06:28 +01:00
return " exit " ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & ( getAllocationType ( tok , varid ) ! = No | | getReallocationType ( tok , varid ) ! = No | | getDeallocationType ( tok , varid ) ! = No ) )
2009-01-15 21:34:39 +01:00
return 0 ;
2010-04-02 07:30:58 +02:00
if ( callstack . size ( ) > 2 )
2009-01-15 21:34:39 +01:00
return " dealloc_ " ;
2009-02-08 12:59:04 +01:00
const std : : string funcname ( tok - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = callstack . begin ( ) ; it ! = callstack . end ( ) ; + + it )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ( * it ) & & ( * it ) - > str ( ) = = funcname )
2009-01-15 21:34:39 +01:00
return " recursive " ;
}
callstack . push_back ( tok ) ;
2009-06-15 17:44:59 +02:00
2009-10-03 21:46:22 +02:00
// lock/unlock..
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-10-03 21:46:22 +02:00
{
const Token * ftok = _tokenizer - > getFunctionTokenByName ( funcname . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
2009-10-03 21:46:22 +02:00
ftok = ftok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! ftok )
2009-10-03 21:46:22 +02:00
return 0 ;
2010-05-16 19:55:16 +02:00
Token * func = getcode ( ftok - > tokAt ( 1 ) , callstack , 0 , alloctype , dealloctype , false , 1 ) ;
simplifycode ( func ) ;
2009-10-03 21:46:22 +02:00
const char * ret = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( func , " ; alloc ; } " ) )
2009-10-03 21:46:22 +02:00
ret = " alloc " ;
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( func , " ; dealloc ; } " ) )
2009-10-03 21:46:22 +02:00
ret = " dealloc " ;
Tokenizer : : deleteTokens ( func ) ;
return ret ;
}
2009-06-12 17:31:29 +02:00
// how many parameters is there in the function call?
int numpar = countParameters ( tok ) ;
2010-04-02 07:30:58 +02:00
if ( numpar < = 0 )
2011-01-11 20:14:15 +01:00
{
// Taking return value => it is not a noreturn function
if ( tok - > strAt ( - 1 ) = = " = " )
return NULL ;
// Function is not noreturn
if ( notnoreturn . find ( funcname ) ! = notnoreturn . end ( ) )
return NULL ;
2011-01-01 20:14:01 +01:00
return ( tok - > previous ( ) - > str ( ) ! = " = " ) ? " callfunc " : NULL ;
2011-01-11 20:14:15 +01:00
}
2009-06-12 17:31:29 +02:00
2010-08-06 18:32:31 +02:00
unsigned int par = 1 ;
unsigned int parlevel = 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
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-01-15 21:34:39 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-01-15 21:34:39 +01:00
{
- - parlevel ;
2010-04-02 07:30:58 +02:00
if ( parlevel < 1 )
2009-02-08 12:59:04 +01:00
{
2011-04-10 15:55:08 +02:00
return ( eq | | _settings - > experimental ) ? 0 : " callfunc " ;
2009-02-08 12:59:04 +01:00
}
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( parlevel = = 1 )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " , " )
2009-01-15 21:34:39 +01:00
+ + par ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " [,()] %varid% [,()] " , varid ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( dot )
2009-10-12 21:36:28 +02:00
return " use " ;
2009-07-05 22:16:43 +02:00
const Token * ftok = _tokenizer - > getFunctionTokenByName ( funcname . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! ftok )
2009-06-23 20:37:34 +02:00
return " use " ;
2009-06-12 17:31:29 +02:00
// how many parameters does the function want?
2010-04-02 07:30:58 +02:00
if ( numpar ! = countParameters ( ftok ) )
2009-06-12 17:31:29 +02:00
return " recursive " ;
2009-01-15 21:34:39 +01:00
const char * parname = Tokenizer : : getParameterName ( ftok , par ) ;
2010-04-02 07:30:58 +02:00
if ( ! parname )
2009-01-15 21:34:39 +01:00
return " recursive " ;
2009-08-19 19:42:07 +02:00
unsigned int parameterVarid = 0 ;
{
const Token * partok = Token : : findmatch ( ftok , parname ) ;
2010-04-02 07:30:58 +02:00
if ( partok )
2009-08-19 19:42:07 +02:00
parameterVarid = partok - > varId ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( parameterVarid = = 0 )
2009-08-19 19:42:07 +02:00
return " recursive " ;
2009-01-15 21:34:39 +01:00
// Check if the function deallocates the variable..
2010-04-02 07:30:58 +02:00
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
2009-01-15 21:34:39 +01:00
ftok = ftok - > next ( ) ;
2011-07-28 08:12:21 +02:00
if ( ! ftok )
return 0 ;
2010-05-16 19:55:16 +02:00
Token * func = getcode ( ftok - > tokAt ( 1 ) , callstack , parameterVarid , alloctype , dealloctype , false , sz ) ;
2010-02-06 22:35:36 +01:00
//simplifycode(func, all);
2009-01-15 21:34:39 +01:00
const Token * func_ = func ;
2010-04-02 07:30:58 +02:00
while ( func_ & & func_ - > str ( ) = = " ; " )
2009-01-15 21:34:39 +01:00
func_ = func_ - > next ( ) ;
const char * ret = 0 ;
2009-07-14 08:17:12 +02:00
/** @todo handle "goto" */
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( func_ , " dealloc " ) )
2009-01-15 21:34:39 +01:00
ret = " dealloc " ;
2010-04-02 07:30:58 +02:00
else if ( Token : : findmatch ( func_ , " use " ) )
2009-01-15 21:34:39 +01:00
ret = " use " ;
2010-04-02 07:30:58 +02:00
else if ( Token : : findmatch ( func_ , " &use " ) )
2009-01-15 21:34:39 +01:00
ret = " &use " ;
Tokenizer : : deleteTokens ( func ) ;
return ret ;
}
2010-06-05 01:58:50 +02:00
if ( varid > 0 & & Token : : Match ( tok , " [,()] & %varid% [,()] " , varid ) )
{
const Token * ftok = _tokenizer - > getFunctionTokenByName ( funcname . c_str ( ) ) ;
2010-06-17 03:29:55 +02:00
AllocType a ;
const char * ret = functionArgAlloc ( ftok , par , a ) ;
2010-06-05 01:58:50 +02:00
if ( a ! = No )
{
if ( alloctype = = No )
alloctype = a ;
else if ( alloctype ! = a )
alloctype = Many ;
allocpar = true ;
2010-06-17 03:29:55 +02:00
return ret ;
2010-06-05 01:58:50 +02:00
}
}
2011-08-25 19:59:44 +02:00
if ( varid > 0 & & Token : : Match ( tok , " [(,] %varid% . %var% [,)] " , varid ) )
return " use " ;
2009-01-15 21:34:39 +01:00
}
}
return NULL ;
}
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
{
Token * rethead = 0 , * rettail = 0 ;
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 ";"
2010-09-04 10:06:34 +02:00
rethead = new Token ( 0 ) ;
rethead - > str ( " ; " ) ;
rethead - > linenr ( tok - > linenr ( ) ) ;
rethead - > fileIndex ( tok - > fileIndex ( ) ) ;
rettail = rethead ;
2009-01-15 21:34:39 +01:00
int indentlevel = 0 ;
int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " { " ) ;
2009-01-15 21:34:39 +01:00
+ + indentlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-15 21:34:39 +01:00
{
2010-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
if ( Token : : Match ( tok , " [;{}] " ) & & varid > 0 & & parlevel = = 0 )
{
if ( Token : : Match ( tok - > next ( ) , " [{};] " ) )
continue ;
// function calls are interesting..
const Token * tok2 = tok ;
while ( Token : : Match ( tok2 - > next ( ) , " %var% . " ) )
tok2 = tok2 - > tokAt ( 2 ) ;
if ( Token : : Match ( tok2 - > next ( ) , " %var% ( " ) )
;
else if ( Token : : Match ( tok - > next ( ) , " continue|break|return|throw|goto|do|else " ) )
;
else
{
const Token * skipToToken = 0 ;
// scan statement for interesting keywords / varid
for ( tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ; " )
{
// nothing interesting found => skip this statement
skipToToken = tok2 - > previous ( ) ;
break ;
}
2011-01-16 09:57:56 +01:00
if ( tok2 - > varId ( ) = = varid | |
2011-01-29 18:46:55 +01: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-01-16 09:56:04 +01:00
if ( skipToToken )
{
tok = skipToToken ;
continue ;
}
}
}
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-08-29 17:33:57 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! callstack . empty ( ) & & Token : : Match ( tok , " [;{}] __cppcheck_lock|__cppcheck_unlock ( ) ; " ) )
2009-08-29 07:02:36 +02:00
{
2009-10-03 21:46:22 +02:00
// Type of leak = Resource leak
alloctype = dealloctype = CheckMemoryLeak : : File ;
2010-04-02 07:30:58 +02:00
if ( tok - > next ( ) - > str ( ) = = " __cppcheck_lock " )
2009-10-03 21:46:22 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " alloc " ) ;
2009-10-03 21:46:22 +02:00
}
else
2009-08-29 07:26:32 +02:00
{
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
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) )
2009-08-29 07:02:36 +02:00
{
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
}
2009-10-03 21:46:22 +02:00
}
else
{
2011-06-29 20:00:21 +02:00
if ( Token : : Match ( tok , " %varid% = close ( %varid% ) " , varid ) )
{
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 ,
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [;{}] %varid% = memcpy|memmove|memset|strcpy|strncpy|strcat|strncat ( %varid% , " , varid ) )
2009-02-07 11:54:39 +01:00
{
2009-10-03 21:46:22 +02:00
tok = tok - > tokAt ( 4 ) - > link ( ) ;
continue ;
2009-02-07 11:54:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > previous ( ) , " [(;{}] %varid% = " , varid ) | |
Token : : Match ( tok , " asprintf ( & %varid% , " , varid ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
CheckMemoryLeak : : AllocType alloc ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " asprintf ( " ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
// todo: check how the return value is used.
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok - > previous ( ) , " [;{}] " ) )
2009-10-03 21:46:22 +02:00
{
Tokenizer : : deleteTokens ( rethead ) ;
return 0 ;
}
alloc = Malloc ;
tok = tok - > next ( ) - > link ( ) ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
else
{
alloc = getAllocationType ( tok - > tokAt ( 2 ) , varid ) ;
}
bool realloc = false ;
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( sz > 1 & &
Token : : Match ( tok - > tokAt ( 2 ) , " malloc ( %num% ) " ) & &
2010-08-06 22:37:48 +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 ) ) ;
}
2010-04-02 07:30:58 +02:00
if ( alloc = = CheckMemoryLeak : : No )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
alloc = getReallocationType ( tok - > tokAt ( 2 ) , varid ) ;
2010-04-02 07:30:58 +02:00
if ( alloc ! = CheckMemoryLeak : : No )
2009-01-31 14:57:27 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " realloc " ) ;
addtoken ( & rettail , tok , " ; " ) ;
2009-10-03 21:46:22 +02:00
realloc = true ;
tok = tok - > tokAt ( 2 ) ;
2011-01-16 09:56:04 +01:00
if ( Token : : Match ( tok , " %var% ( " ) )
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..
2010-04-02 07:30:58 +02:00
if ( alloc = = CheckMemoryLeak : : New )
2009-10-03 21:46:22 +02:00
{
2011-08-07 01:10:15 +02:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " new struct| %type% [(;] " ) )
2009-10-03 21:46:22 +02:00
{
2011-08-07 01:10:15 +02:00
const int offset = tok - > strAt ( 3 ) = = " struct " ? 1 : 0 ;
if ( isclass ( _tokenizer , tok - > tokAt ( 3 + offset ) , varid ) )
2009-10-03 21:46:22 +02:00
{
2010-05-16 07:15:31 +02:00
alloc = No ;
2009-02-20 07:28:18 +01:00
}
2009-01-31 14:57:27 +01:00
}
2011-08-07 01:10:15 +02:00
else if ( Token : : Match ( tok - > tokAt ( 2 ) , " new ( nothrow ) struct| %type% " ) )
2010-07-05 14:01:25 +02:00
{
2011-08-07 01:10:15 +02:00
const int offset = tok - > strAt ( 6 ) = = " struct " ? 1 : 0 ;
if ( isclass ( _tokenizer , tok - > tokAt ( 6 + offset ) , varid ) )
2010-07-05 14:01:25 +02:00
{
alloc = No ;
}
}
2011-08-07 01:10:15 +02:00
else if ( Token : : Match ( tok - > tokAt ( 2 ) , " new ( std :: nothrow ) struct| %type% " ) )
2010-07-05 14:01:25 +02:00
{
2011-08-07 01:10:15 +02:00
const int offset = tok - > strAt ( 8 ) = = " struct " ? 1 : 0 ;
if ( isclass ( _tokenizer , 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
}
2010-04-02 07:30:58 +02:00
if ( alloc ! = No )
2009-10-03 21:46:22 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! realloc )
2010-09-04 10:06:34 +02:00
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
2010-04-02 07:30:58 +02:00
if ( alloc ! = Many & & dealloctype ! = No & & dealloctype ! = Many & & dealloctype ! = alloc )
2009-10-03 21:46:22 +02:00
{
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) - > str ( ) ) ;
2009-10-03 21:46:22 +02:00
callstack . pop_back ( ) ;
}
alloctype = alloc ;
2010-06-06 11:22:59 +02:00
if ( Token : : Match ( tok , " %var% = %type% ( " ) )
{
tok = tok - > tokAt ( 3 ) - > link ( ) ;
continue ;
}
2009-10-03 21:46:22 +02:00
}
// assignment..
else
{
// is the pointer in rhs?
bool rhs = false ;
2010-11-20 08:35:23 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-10-03 21:46:22 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ; " )
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
2011-05-29 17:44:10 +02:00
if ( Token : : Match ( tok2 , " [=+(,] %varid% " , varid ) )
2009-10-03 21:46:22 +02:00
{
2011-08-28 11:28:14 +02:00
if ( ! rhs & & Token : : Match ( tok2 , " [(,] " ) )
{
addtoken ( & rettail , tok , " use " ) ;
addtoken ( & rettail , tok , " ; " ) ;
}
2009-10-03 21:46:22 +02:00
rhs = true ;
}
}
2010-11-20 08:35:23 +01:00
if ( ! rhs )
addtoken ( & rettail , tok , " assign " ) ;
continue ;
2009-10-03 21:46:22 +02:00
}
2009-01-25 21:57:34 +01:00
}
2011-01-16 09:56:04 +01:00
if ( Token : : Match ( tok - > previous ( ) , " [;{})=|] %var% " ) )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
AllocType dealloc = getDeallocationType ( tok , varid ) ;
2010-01-07 21:36:51 +01:00
2010-04-02 07:30:58 +02:00
if ( dealloc ! = No & & tok - > str ( ) = = " fcloseall " & & alloctype ! = dealloc )
2010-01-07 21:36:51 +01:00
dealloc = No ;
2010-04-02 07:30:58 +02:00
else if ( dealloc ! = No )
2009-01-15 21:34:39 +01:00
{
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 ;
2010-04-02 07:30:58 +02:00
if ( dealloc ! = Many & & alloctype ! = No & & alloctype ! = Many & & alloctype ! = dealloc )
2009-01-15 21:34:39 +01:00
{
2009-10-03 21:46:22 +02:00
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) - > str ( ) ) ;
2009-10-03 21:46:22 +02:00
callstack . pop_back ( ) ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
dealloctype = dealloc ;
2011-01-16 09:57:56 +01:00
2011-01-16 09:56:04 +01:00
if ( tok - > strAt ( 2 ) = = " ( " )
2011-01-16 09:57:56 +01:00
tok = tok - > tokAt ( 2 ) - > link ( ) ;
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-07-31 19:38:39 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( alloctype = = Fd )
2009-02-01 16:47:36 +01:00
{
2010-11-30 19:14:09 +01:00
if ( Token : : Match ( tok , " if ( 0 <=|< %varid% ) " , varid ) | |
2010-04-02 07:30:58 +02:00
Token : : Match ( tok , " if ( %varid% != -1 ) " , varid ) )
2009-10-03 21:46:22 +02:00
{
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 ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " if ( %varid% == -1 ) " , varid ) | |
Token : : Match ( tok , " if ( %varid% < 0 ) " , varid ) )
2009-10-03 21:46:22 +02:00
{
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
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( %varid% ) " , varid ) )
2009-08-29 09:18:21 +02:00
{
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 ;
2009-08-29 09:18:21 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok , " if ( " ) & & notvar ( tok - > tokAt ( 2 ) , varid , true ) )
2009-08-29 09:18:21 +02:00
{
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".
for ( const Token * tok2 = tok - > next ( ) - > link ( ) - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
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 ;
2009-08-29 09:18:21 +02:00
}
2009-10-03 21:46:22 +02:00
else
2009-01-15 21:34:39 +01:00
{
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 ;
2010-04-06 22:17:23 +02:00
int innerParlevel = 0 ;
2010-12-22 18:32:00 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2010-04-06 22:17:23 +02:00
+ + innerParlevel ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ) " )
2009-10-03 21:46:22 +02:00
{
2010-04-06 22:17:23 +02:00
- - innerParlevel ;
if ( innerParlevel < = 0 )
2009-10-03 21:46:22 +02:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " close|pclose|fclose|closedir ( %varid% ) " , varid ) )
2009-10-03 21:46:22 +02:00
{
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 ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
if ( alloctype = = Fd & & Token : : Match ( tok2 , " %varid% !=|>= " , varid ) )
2009-10-03 21:46:22 +02:00
{
dep = true ;
}
2010-04-06 22:17:23 +02:00
if ( innerParlevel > 0 & & Token : : Match ( tok2 , " ! %varid% " , varid ) )
2010-03-13 17:11:48 +01:00
{
dep = true ;
}
2010-05-31 18:20:34 +02:00
if ( innerParlevel > 0 & & Token : : Match ( tok2 , " %var% ( " ) & & ! test_white_list ( tok2 - > str ( ) ) )
2010-05-24 19:28:27 +02:00
{
bool use = false ;
for ( const Token * tok3 = tok2 - > tokAt ( 2 ) ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) = = " ( " )
tok3 = tok3 - > link ( ) ;
else if ( tok3 - > str ( ) = = " ) " )
break ;
2010-12-17 21:34:22 +01:00
else if ( Token : : Match ( tok3 - > previous ( ) , " (|, &| %varid% ,|) " , varid ) )
2010-05-24 19:28:27 +02:00
{
use = true ;
break ;
}
}
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-01-10 19:35:06 +01:00
if ( tok2 - > varId ( ) & & extravar . find ( tok2 - > varId ( ) ) ! = extravar . end ( ) )
{
dep = true ;
}
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( ! %varid% && " , varid ) )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if(!var) " ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > next ( ) & &
tok - > next ( ) - > link ( ) & &
Token : : Match ( tok - > next ( ) - > link ( ) - > tokAt ( - 3 ) , " && ! %varid% " , varid ) )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " if(!var) " ) ;
2009-01-15 21:34:39 +01:00
}
2009-10-03 21:46:22 +02:00
else
2009-08-29 09:18:21 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , ( dep ? " ifv " : " if " ) ) ;
2009-08-29 09:18:21 +02:00
}
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
}
}
}
2010-04-02 07:30:58 +02:00
if ( ( tok - > str ( ) = = " else " ) | | ( tok - > str ( ) = = " switch " ) )
2009-01-15 21:34:39 +01:00
{
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-01-16 09:56:04 +01:00
if ( ( tok - > str ( ) = = " case " ) )
2009-01-15 21:34:39 +01:00
{
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-01-16 09:56:04 +01:00
if ( ( tok - > str ( ) = = " default " ) )
2009-01-15 21:34:39 +01:00
{
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..
2010-04-02 07:30:58 +02:00
else if ( ( tok - > str ( ) = = " for " ) | | ( tok - > str ( ) = = " while " ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " while ( true ) " ) | |
Token : : simpleMatch ( tok , " for ( ; ; ) " ) )
2009-09-27 21:49:07 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while1 " ) ;
2009-09-27 21:49:07 +02:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-01-24 21:48:39 +01:00
2010-05-29 21:11:59 +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
}
2010-04-02 07:30:58 +02:00
else if ( alloctype = = Fd & & varid )
2010-01-24 21:48:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " while ( 0 <= %varid% ) " , varid ) | |
Token : : Match ( tok , " while ( %varid% != -1 ) " , varid ) )
2010-01-24 21:48:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(var) " ) ;
2010-01-24 21:48:39 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " while ( %varid% == -1 ) " , varid ) | |
Token : : Match ( tok , " while ( %varid% < 0 ) " , varid ) )
2010-01-24 21:48:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(!var) " ) ;
2010-01-24 21:48:39 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : Match ( tok , " while ( %varid% ) " , varid ) )
2010-01-24 21:48:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(var) " ) ;
2010-01-24 21:48:39 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : simpleMatch ( tok , " while ( " ) & & notvar ( tok - > tokAt ( 2 ) , varid , true ) )
2010-01-24 21:48:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " while(!var) " ) ;
2010-01-24 21:48:39 +01:00
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " loop " ) ;
2011-01-16 09:57:56 +01:00
2011-01-16 09:56:04 +01:00
if ( varid > 0 )
{
unsigned int parlevel2 = 0 ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel2 ;
else if ( tok2 - > str ( ) = = " ) " )
{
if ( parlevel2 > 0 )
- - parlevel2 ;
else
break ;
}
if ( notvar ( tok2 , varid ) )
{
addtoken ( & rettail , tok2 , " !var " ) ;
break ;
}
}
}
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-01-16 09:56:04 +01:00
if ( ( tok - > str ( ) = = " do " ) )
2009-01-15 21:34:39 +01:00
{
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..
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " continue " )
2009-10-03 21:46:22 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " continue " ) ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " break " )
2009-10-03 21:46:22 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " break " ) ;
2009-10-03 21:46:22 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " goto " )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " goto " ) ;
2009-01-15 21:34:39 +01:00
}
// Return..
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " return " )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " return " ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-10-03 21:46:22 +02:00
{
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..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) , " std :: auto_ptr < " ) )
2009-04-28 20:01:35 +02:00
{
const Token * tok2 = tok - > tokAt ( 5 ) ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " > " )
2009-04-28 20:01:35 +02:00
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " > ( %varid% ) " , varid ) )
2009-04-28 20:01:35 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
2009-04-28 20:01:35 +02:00
tok = tok2 - > tokAt ( 3 ) ;
}
}
2010-04-02 07:30:58 +02:00
else if ( varid & & Token : : Match ( tok , " return strcpy|strncpy|memcpy ( %varid% " , varid ) )
2009-07-24 21:55:35 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
2009-07-24 21:55:35 +02:00
tok = tok - > tokAt ( 2 ) ;
}
else
2009-01-15 21:34:39 +01:00
{
2010-08-04 23:01:32 +02:00
bool use = false ;
2010-08-05 21:23:32 +02:00
std : : stack < const Token * > f ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ; " )
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 ( ) = = " ( " )
f . push ( tok2 - > previous ( ) ) ;
2010-10-21 19:42:09 +02:00
else if ( ! f . empty ( ) & & tok2 - > str ( ) = = " ) " )
2010-08-05 21:23:32 +02:00
f . pop ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) = = varid )
2009-01-15 21:34:39 +01:00
{
2010-08-04 23:01:32 +02:00
// Read data..
if ( ! Token : : Match ( tok2 - > previous ( ) , " &|( " ) & &
Token : : simpleMatch ( tok2 - > next ( ) , " [ " ) )
{
}
2010-11-11 17:40:20 +01:00
else if ( f . empty ( ) | |
! test_white_list ( f . top ( ) - > str ( ) ) | |
getDeallocationType ( f . 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..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " try|throw|catch " ) )
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , tok - > str ( ) ) ;
2009-01-15 21:34:39 +01:00
// Assignment..
2010-04-02 07:30:58 +02:00
if ( varid )
2009-01-15 21:34:39 +01:00
{
2011-02-02 17:12:46 +01:00
if ( Token : : simpleMatch ( tok , " = { " ) )
2010-10-20 18:39:40 +02:00
{
unsigned int indentlevel2 = 0 ;
bool use = false ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
else if ( tok2 - > str ( ) = = " } " )
{
if ( indentlevel2 < = 1 )
break ;
- - indentlevel2 ;
}
else if ( tok2 - > varId ( ) = = varid )
{
use = true ;
break ;
}
}
if ( use )
{
addtoken ( & rettail , tok , " use " ) ;
addtoken ( & rettail , tok , " ; " ) ;
tok = tok - > next ( ) - > link ( ) ;
continue ;
}
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [)=] %varid% [+;)] " , varid ) | |
Token : : Match ( tok , " %var% + %varid% " , varid ) | |
Token : : Match ( tok , " %varid% +=|-= " , varid ) | |
Token : : Match ( tok , " +=|<< %varid% ; " , varid ) | |
2010-06-21 18:43:28 +02:00
Token : : Match ( tok , " = strcpy|strcat|memmove|memcpy ( %varid% , " , varid ) | |
Token : : Match ( tok , " [;{}] %var% [ %varid% ] " , varid ) )
2009-08-25 21:44:19 +02:00
{
2010-11-29 19:53:34 +01:00
addtoken ( & rettail , tok , " use " ) ;
2009-08-25 21:44:19 +02:00
}
2011-04-09 18:47:01 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " ; | { | } | = | ( | , | % op % % varid % [ " , varid))
2009-08-25 21:44:19 +02:00
{
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..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% ( " ) )
2009-01-15 21:34:39 +01:00
{
2009-11-15 10:30:00 +01:00
// A function call should normally be followed by ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) )
2009-11-15 10:30:00 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " if|for|while|switch " ) )
2009-11-15 10:30:00 +01:00
{
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
else if ( Token : : Match ( tok , " setjmp|longjmp " ) )
{
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
2010-04-02 07:30:58 +02:00
else if ( classmember )
2009-01-15 21:34:39 +01:00
{
2010-11-10 18:24:40 +01:00
if ( noreturn . find ( tok - > str ( ) ) ! = noreturn . end ( ) )
addtoken ( & rettail , tok , " exit " ) ;
else if ( ! test_white_list ( tok - > str ( ) ) )
2009-01-15 21:34:39 +01:00
{
2010-09-08 20:03:22 +02:00
int innerParlevel = 1 ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-09-08 20:03:22 +02:00
if ( tok2 - > str ( ) = = " ( " )
+ + innerParlevel ;
else if ( tok2 - > str ( ) = = " ) " )
{
- - innerParlevel ;
if ( innerParlevel < = 0 )
break ;
}
if ( tok2 - > varId ( ) = = varid )
{
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
}
}
}
else
{
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " %var% ( close|fclose|pclose ( %varid% ) ) ; " , varid ) )
2009-10-04 13:10:08 +02:00
{
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 ) ;
2010-04-02 07:30:58 +02:00
if ( str )
2009-08-02 22:30:43 +02:00
{
2010-06-17 03:29:55 +02:00
if ( allocpar )
2009-10-03 21:46:22 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , str ) ;
2010-06-17 03:29:55 +02:00
tok = tok - > next ( ) - > link ( ) ;
2009-10-03 21:46:22 +02:00
}
2010-06-17 03:29:55 +02:00
else if ( varid = = 0 | | str ! = std : : string ( " alloc " ) )
2009-08-02 22:30:43 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , str ) ;
2009-08-02 22:30:43 +02:00
}
2010-06-17 03:29:55 +02:00
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %varid% = " , varid ) )
2010-06-05 01:58:50 +02:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , str ) ;
2010-06-05 01:58:50 +02:00
}
2009-08-02 22:30:43 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( varid > 0 & &
getReallocationType ( tok , varid ) ! = No & &
tok - > tokAt ( 2 ) - > varId ( ) = = varid )
2009-10-03 21:46:22 +02:00
{
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..
2011-03-06 09:42:16 +01:00
if ( Token : : Match ( tok , " ( *| %var% " ) & & Token : : simpleMatch ( tok - > link ( ) , " ) ( " ) )
2009-01-15 21:34:39 +01:00
{
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
2011-03-06 09:42:16 +01:00
while ( Token : : Match ( tok2 , " . %var% " ) )
tok2 = tok2 - > tokAt ( 2 ) ;
2009-01-15 21:34:39 +01:00
2011-03-06 09:42:16 +01:00
if ( Token : : simpleMatch ( tok2 , " ) ( " ) )
2009-01-15 21:34:39 +01:00
{
2011-03-06 09:42:16 +01:00
for ( ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{] " ) )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > varId ( ) = = varid )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " use " ) ;
2009-01-15 21:34:39 +01:00
break ;
}
}
}
}
// Linux lists..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " [=(,] & %varid% [.[,)] " , varid ) )
2009-01-15 21:34:39 +01:00
{
2010-09-04 10:06:34 +02:00
addtoken ( & rettail , tok , " &use " ) ;
2009-01-15 21:34:39 +01:00
}
}
2010-11-30 19:36:04 +01:00
for ( Token * tok1 = rethead ; tok1 ; tok1 = tok1 - > next ( ) )
{
if ( Token : : simpleMatch ( tok1 , " callfunc alloc ; " ) )
{
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
2010-05-16 19:55:16 +02:00
void CheckMemoryLeakInFunction : : simplifycode ( Token * tok )
2009-01-15 21:34:39 +01:00
{
{
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 ;
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2011-01-01 12:27:57 +01:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < = trylevel )
trylevel = - 1 ;
}
else if ( trylevel = = - 1 & & tok2 - > str ( ) = = " try " )
trylevel = indentlevel ;
else if ( trylevel = = - 1 & & tok2 - > str ( ) = = " throw " )
tok2 - > str ( " return " ) ;
2009-01-15 21:34:39 +01:00
}
}
2010-09-12 21:04:05 +02:00
// Insert extra ";"
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( ! tok2 - > previous ( ) | | Token : : Match ( tok2 - > previous ( ) , " [;{}] " ) )
{
if ( Token : : Match ( tok2 , " assign|callfunc|use assign|callfunc|use " ) )
{
tok2 - > insertToken ( " ; " ) ;
}
}
}
2010-04-27 20:43:31 +02:00
// remove redundant braces..
for ( Token * start = tok ; start ; start = start - > next ( ) )
{
if ( Token : : simpleMatch ( start , " ; { " ) )
{
// the "link" doesn't work here. Find the end brace..
unsigned int indent = 0 ;
for ( Token * end = start ; end ; end = end - > next ( ) )
{
if ( end - > str ( ) = = " { " )
+ + indent ;
else if ( end - > str ( ) = = " } " )
{
if ( indent < = 1 )
{
2011-01-01 13:28:34 +01:00
// If the start/end braces are redundant, delete them
2010-04-27 20:43:31 +02:00
if ( indent = = 1 & & Token : : Match ( end - > previous ( ) , " [;{}] } %any% " ) )
{
start - > deleteNext ( ) ;
end - > deleteThis ( ) ;
}
break ;
}
- - indent ;
}
}
}
}
2009-01-15 21:34:39 +01:00
// reduce the code..
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 ;
2010-04-02 07:30:58 +02:00
while ( ! done )
2009-01-15 21:34:39 +01:00
{
2009-06-20 13:58:30 +02:00
//tok->printOut("simplifycode loop..");
2009-01-15 21:34:39 +01:00
done = true ;
2010-09-11 20:49:24 +02:00
// reduce callfunc
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " callfunc " )
{
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
2010-09-12 21:41:13 +02:00
if ( Token : : Match ( tok , " ;| if return ; " ) )
{
tok - > deleteThis ( ) ;
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..
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2010-01-14 21:41:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 { " ) )
2010-01-14 21:41:50 +01:00
{
2010-04-06 22:17:23 +02:00
unsigned int innerIndentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( Token * tok3 = tok2 - > tokAt ( 2 ) ; tok3 ; tok3 = tok3 - > next ( ) )
2010-01-14 21:41:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2010-04-06 22:17:23 +02:00
+ + innerIndentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2010-01-14 21:41:50 +01:00
{
2010-04-06 22:17:23 +02:00
if ( innerIndentlevel = = 0 )
2010-01-14 21:41:50 +01:00
break ;
2010-04-06 22:17:23 +02:00
- - innerIndentlevel ;
2010-01-14 21:41:50 +01:00
}
2010-04-06 22:17:23 +02:00
while ( innerIndentlevel = = 0 & & Token : : Match ( tok3 , " [{};] if|ifv|else { continue ; } " ) )
2010-01-14 21:41:50 +01:00
{
Token : : eraseTokens ( tok3 , tok3 - > tokAt ( 6 ) ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok3 - > next ( ) , " else " ) )
2010-01-14 21:41:50 +01:00
tok3 - > deleteNext ( ) ;
}
}
2011-02-02 17:12:46 +01:00
if ( Token : : simpleMatch ( tok2 , " while1 { if { dealloc ; return ; } } " ) )
2010-01-14 21:41:50 +01:00
{
tok2 - > str ( " ; " ) ;
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
Token : : eraseTokens ( tok2 - > tokAt ( 4 ) , tok2 - > tokAt ( 7 ) ) ;
}
}
}
2011-01-01 13:28:34 +01:00
// Main inner simplification loop
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 ? tok2 - > next ( ) : NULL )
2009-01-15 21:34:39 +01:00
{
// Delete extra ";"
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " [;{}] ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace "{ }" with ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " { } " ) )
2009-01-15 21:34:39 +01:00
{
2010-01-10 20:03:46 +01:00
tok2 - > eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
tok2 - > insertToken ( " ; " ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Delete braces around a single instruction..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " { %var% ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-06-14 08:20:51 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 2 ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " { %var% %var% ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-06-14 08:12:04 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-23 22:42:07 +02:00
// Reduce "if if|callfunc" => "if"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " if if|callfunc " ) )
2009-06-16 19:05:05 +02:00
{
2009-09-23 22:42:07 +02:00
tok2 - > deleteNext ( ) ;
2009-06-16 19:05:05 +02:00
done = false ;
}
2009-01-15 21:34:39 +01:00
2011-04-20 17:16:09 +02:00
// outer/inner if blocks. Remove outer condition..
else if ( Token : : Match ( tok2 - > next ( ) , " if|if(var) { if return use ; } " ))
{
tok2 - > tokAt ( 6 ) - > deleteNext ( ) ;
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2010-04-02 07:30:58 +02:00
else if ( tok2 - > next ( ) & & tok2 - > next ( ) - > str ( ) = = " if " )
2009-01-15 21:34:39 +01:00
{
// Delete empty if that is not followed by an else
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-26 07:19:22 +02:00
// Reduce "if X ; else X ;" => "X ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if %var% ; else % var % ; " ) &&
std : : string ( tok2 - > strAt ( 2 ) ) = = std : : string ( tok2 - > strAt ( 5 ) ) )
2009-09-26 07:19:22 +02:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 5 ) ) ;
done = false ;
}
2010-11-27 11:09:42 +01:00
// Reduce "if continue ; if continue ;" => "if continue ;"
2011-02-02 17:12:46 +01:00
else if ( Token : : simpleMatch ( tok2 - > next ( ) , " if continue ; if continue ; " ))
2010-11-27 11:09:42 +01:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Reduce "if return ; alloc ;" => "alloc ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if return ; alloc|return ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if alloc ; else return ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ; // Remove "if"
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 5 ) ) ; // Remove "; else return"
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if ; else %var% ;" => "if %var% ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if ; else % var % ; " ))
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-08-29 16:27:16 +02:00
// Reduce "if ; else" => "if"
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok2 - > next ( ) , " if ; else " ))
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-01-12 19:12:08 +01:00
// Reduce "if return ; else|if return|continue ;" => "if return ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if return ; else | if return | continue | break ; " ))
2009-01-15 21:34:39 +01:00
{
2010-01-12 19:12:08 +01:00
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 6 ) ) ;
done = false ;
}
// Reduce "if continue|break ; else|if return ;" => "if return ;"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " if continue|break ; if | else return ; " ))
2010-01-12 19:12:08 +01:00
{
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-11-27 11:09:42 +01:00
// Remove "else" after "if continue|break|return"
else if ( Token : : Match ( tok2 - > next ( ) , " if continue|break|return ; else " ))
{
tok2 - > tokAt ( 4 ) - > deleteThis ( ) ;
done = false ;
}
2009-09-01 20:02:28 +02:00
// Delete "if { dealloc|assign|use ; return ; }"
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " [;{}] if { dealloc|assign|use ; return ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 8 ) ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " else " ) )
2009-12-13 19:50:49 +01:00
tok2 - > deleteNext ( ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2011-08-02 09:04:13 +02:00
// Remove "if { dealloc ; callfunc ; } !!else|return"
else if ( Token : : Match ( tok2 - > next ( ) , " if { dealloc | assign ; callfunc ; } " ) &&
! Token : : Match ( tok2 - > tokAt ( 8 ) , " else|return " ) )
2009-02-08 19:27:09 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 8 ) ) ;
2009-02-08 19:27:09 +01:00
done = false ;
}
2009-01-15 21:34:39 +01:00
continue ;
}
2010-01-24 21:48:39 +01:00
// Reduce "alloc while(!var) alloc ;" => "alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc ; while(!var) alloc ; " ) )
2010-01-19 19:08:03 +01:00
{
2010-01-24 21:48:39 +01:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2010-01-19 19:08:03 +01:00
done = false ;
2010-03-13 17:11:48 +01:00
}
// Reduce "ifv return;" => "if return use;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " ifv return ; " ) )
2010-03-13 17:11:48 +01:00
{
tok2 - > str ( " if " ) ;
tok2 - > next ( ) - > insertToken ( " use " ) ;
done = false ;
2010-01-19 19:08:03 +01:00
}
2009-01-15 21:34:39 +01:00
// Reduce "if(var) dealloc ;" and "if(var) use ;" that is not followed by an else..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] if(var) assign|dealloc|use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "; if(!var) alloc ; !!else" => "; dealloc ; alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; if(!var) alloc ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
// Remove the "if(!var)"
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
// Insert "dealloc ;" before the "alloc ;"
tok2 - > insertToken ( " ; " ) ;
tok2 - > insertToken ( " dealloc " ) ;
done = false ;
}
2009-08-29 16:03:23 +02:00
// Reduce "; if(!var) exit ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; if(!var) exit ; " ) )
2009-08-29 16:03:23 +02:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2009-08-29 16:27:16 +02:00
// Reduce "if* ;"..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var)|if(!var)|ifv ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-08-29 16:27:16 +02:00
// Followed by else..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > tokAt ( 3 ) , " else " ) )
2009-08-29 16:27:16 +02:00
{
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " if(var) " )
2009-08-29 16:27:16 +02:00
tok2 - > str ( " if(!var) " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " if(!var) " )
2009-08-29 16:27:16 +02:00
tok2 - > str ( " if(var) " ) ;
// remove the "; else"
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
}
else
{
2011-03-09 19:53:59 +01:00
// remove the "if*"
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-08-29 16:27:16 +02:00
}
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "else ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " else ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-11-10 17:46:40 +01:00
// Reduce "while1 continue| ;" => "use ;"
2010-12-08 21:02:02 +01: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 ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " while1 if break ; " ) )
2010-01-14 21:41:50 +01:00
{
tok2 - > str ( " ; " ) ;
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete if block: "alloc; if return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc ; if return use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-22 18:09:29 +02:00
// Reduce "alloc|dealloc|use|callfunc ; exit ;" => "; exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc|dealloc|use|callfunc ; exit ; " ) )
2009-07-23 16:30:30 +02:00
{
2010-02-20 10:17:45 +01:00
tok2 - > deleteNext ( ) ;
2009-07-23 16:30:30 +02:00
done = false ;
}
// Reduce "alloc|dealloc|use ; if(var) exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc|dealloc|use ; if(var) exit ; " ) )
2009-07-23 16:30:30 +02:00
{
tok2 - > deleteThis ( ) ;
done = false ;
}
// Remove "if exit ;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " if exit ; " ) )
2009-07-23 16:30:30 +02:00
{
tok2 - > deleteThis ( ) ;
tok2 - > deleteThis ( ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Remove the "if break|continue ;" that follows "dealloc ; alloc ;"
2011-04-10 15:55:08 +02:00
if ( ! _settings - > experimental & & Token : : Match ( tok2 , " dealloc ; alloc ; if break|continue ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-14 08:12:04 +02:00
tok2 = tok2 - > tokAt ( 3 ) ;
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:48:40 +02:00
// if break ; break ; => break ;
if ( Token : : Match ( tok2 - > previous ( ) , " [;{}] if break ; break ; " ) )
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
done = false ;
}
2010-01-24 21:48:39 +01:00
// Reduce "do { dealloc ; alloc ; } while(var) ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " do { dealloc ; alloc ; } while(var) ; " ) )
2010-01-24 21:48:39 +01:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 9 ) ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Reduce "do { alloc ; } " => "alloc ;"
2009-07-14 08:17:12 +02:00
/** @todo If the loop "do { alloc ; }" can be executed twice, reduce it to "loop alloc ;" */
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " do { alloc ; } " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-06-14 08:20:51 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 2 ) , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-09-26 07:19:22 +02:00
// Reduce "loop break ; => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop break|continue ; " ) )
2009-09-26 07:19:22 +02:00
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
done = false ;
}
2010-01-10 15:40:50 +01:00
// Reduce "loop|do ;" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " loop|do ; " ) )
2010-01-10 14:00:32 +01:00
{
2010-01-10 15:40:50 +01:00
tok2 - > deleteThis ( ) ;
2010-01-10 14:00:32 +01:00
done = false ;
}
2010-09-12 21:15:19 +02:00
// Reduce "loop if break|continue ; !!else" => ";"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " loop if break|continue ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-12 21:15:19 +02:00
// Reduce "loop { if break|continue ; !!else" => "loop {"
if ( Token : : Match ( tok2 , " loop { if break|continue ; !!else " ) )
{
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 5 ) ) ;
done = false ;
}
2009-09-15 22:26:38 +02:00
// Replace "do ; loop ;" with ";"
2010-06-05 11:25:47 +02:00
if ( Token : : simpleMatch ( tok2 , " ; loop ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-09-15 22:26:38 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:07:35 +02:00
// Replace "loop loop .." with "loop .."
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 ;"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 - > next ( ) , " loop if return " ) )
2009-01-17 08:55:40 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-17 08:55:40 +01:00
done = false ;
2009-01-15 21:34:39 +01:00
}
2010-08-02 22:14:51 +02:00
// Reduce "loop|while1 { dealloc ; alloc ; }"
if ( Token : : Match ( tok2 , " loop|while1 { dealloc ; alloc ; } " ) )
{
// delete "loop|while1"
tok2 - > deleteThis ( ) ;
// delete "{"
tok2 - > deleteThis ( ) ;
// delete "}"
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 5 ) ) ;
done = false ;
}
2010-09-12 20:45:30 +02:00
// loop { use ; callfunc ; } => use ;
// assume that the "callfunc" is not noreturn
if ( Token : : simpleMatch ( tok2 , " loop { use ; callfunc ; } " ) )
{
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 7 ) ) ;
tok2 - > str ( " use " ) ;
tok2 - > insertToken ( " ; " ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete if block in "alloc ; if(!var) return ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " alloc ; if(!var) return ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "[;{}] return use ; %var%" => "[;{}] return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] return use ; %var% " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-14 08:12:04 +02:00
Token : : eraseTokens ( tok2 - > tokAt ( 3 ) , tok2 - > tokAt ( 5 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Reduce "if(var) return use ;" => "return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " if(var) return use ; !!else " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2009-02-07 10:44:57 +01:00
// malloc - realloc => alloc ; dealloc ; alloc ;
// Reduce "[;{}] alloc ; dealloc ; alloc ;" => "[;{}] alloc ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] alloc ; dealloc ; alloc ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 - > next ( ) , tok2 - > tokAt ( 6 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-08 19:22:03 +02:00
// use; dealloc; => dealloc;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] use ; dealloc ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:32:21 +02:00
// use use => use
if ( Token : : simpleMatch ( tok2 , " use use " ) )
{
tok2 - > deleteThis ( ) ;
done = false ;
}
2010-09-11 20:18:16 +02:00
// use; if| use; => use;
while ( Token : : Match ( tok2 , " [;{}] use ; if| use ; " ) )
{
Token * t = tok2 - > tokAt ( 2 ) ;
t - > deleteNext ( ) ;
t - > deleteNext ( ) ;
if ( t - > strAt ( 1 ) = = " ; " )
t - > deleteNext ( ) ;
done = false ;
}
2009-01-15 21:34:39 +01:00
// Delete first part in "use ; return use ;"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] use ; return use ; " ) )
2009-01-15 21:34:39 +01:00
{
2010-09-08 19:22:03 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
2010-09-11 21:07:35 +02:00
// try/catch
if ( Token : : simpleMatch ( tok2 , " try ; catch exit ; " ) )
2010-09-11 20:49:24 +02:00
{
2010-09-11 21:07:35 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 4 ) ) ;
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 ;"
2010-04-02 07:30:58 +02:00
while ( Token : : simpleMatch ( tok2 , " case ; case ; " ) )
2009-01-15 21:34:39 +01:00
{
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 3 ) ) ;
2009-01-15 21:34:39 +01:00
done = false ;
}
// Replace switch with if (if not complicated)
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " switch { " ) )
2009-01-15 21:34:39 +01:00
{
// Right now, I just handle if there are a few case and perhaps a default.
bool valid = false ;
bool incase = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * _tok = tok2 - > tokAt ( 2 ) ; _tok ; _tok = _tok - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( _tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( _tok - > str ( ) = = " } " )
2009-01-15 21:34:39 +01:00
{
valid = true ;
break ;
}
2010-04-02 07:30:58 +02:00
else if ( _tok - > str ( ) = = " switch " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( _tok - > str ( ) = = " loop " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( incase & & _tok - > str ( ) = = " case " )
2009-01-15 21:34:39 +01:00
break ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( _tok , " return !!; " ) )
2010-01-10 10:37:54 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( _tok , " if return|break use| ; " ) )
2010-01-10 15:40:50 +01:00
_tok = _tok - > tokAt ( 2 ) ;
2009-07-27 11:24:24 +02:00
incase | = ( _tok - > str ( ) = = " case " ) ;
2010-01-10 10:37:54 +01:00
incase & = ( _tok - > str ( ) ! = " break " & & _tok - > str ( ) ! = " return " ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ! incase & & valid )
2009-01-15 21:34:39 +01:00
{
done = false ;
tok2 - > str ( " ; " ) ;
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
tok2 = tok2 - > next ( ) ;
bool first = true ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " case|default " ) )
2009-01-15 21:34:39 +01:00
{
2010-01-10 10:37:54 +01:00
const bool def ( tok2 - > str ( ) = = " default " ) ;
2009-01-15 21:34:39 +01:00
tok2 - > str ( first ? " if " : " } " ) ;
2010-04-02 07:30:58 +02:00
if ( first )
2009-01-15 21:34:39 +01:00
{
first = false ;
tok2 - > insertToken ( " { " ) ;
}
else
{
// Insert "else [if] {
tok2 - > insertToken ( " { " ) ;
2010-04-02 07:30:58 +02:00
if ( ! def )
2009-01-15 21:34:39 +01:00
tok2 - > insertToken ( " if " ) ;
tok2 - > insertToken ( " else " ) ;
tok2 = tok2 - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
while ( tok2 )
2010-01-10 15:40:50 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " } " )
2010-01-10 15:40:50 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " break|return ; " ) )
2010-01-10 15:40:50 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " if return|break use| ; " ) )
2010-01-10 15:40:50 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
else
tok2 = tok2 - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " break ; " ) )
2009-01-15 21:34:39 +01:00
{
tok2 - > str ( " ; " ) ;
2009-06-14 08:20:51 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( tok2 & & tok2 - > str ( ) = = " return " )
2010-01-10 10:37:54 +01:00
{
tok2 = tok2 - > tokAt ( 2 ) ;
}
2009-01-15 21:34:39 +01:00
}
}
}
}
2009-07-23 16:30:30 +02:00
2009-09-23 22:42:07 +02:00
// If "--all" is given, remove all "callfunc"..
2011-04-10 15:55:08 +02:00
if ( done & & _settings - > experimental )
2009-09-23 22:42:07 +02:00
{
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-09-23 22:42:07 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " callfunc " )
2009-09-23 22:42:07 +02:00
{
tok2 - > deleteThis ( ) ;
done = false ;
}
}
}
}
2009-01-15 21:34:39 +01:00
}
2010-05-16 19:55:16 +02:00
const Token * CheckMemoryLeakInFunction : : findleak ( const Token * tokens )
2009-08-23 15:48:25 +02:00
{
2009-10-08 22:30:33 +02:00
const Token * result ;
2009-08-23 15:48:25 +02:00
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " loop alloc ; " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
return result ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tokens , " alloc ; if|if(var)|ifv break|continue|return ; " ) )
2009-11-15 10:30:00 +01:00
{
return tokens - > tokAt ( 3 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; if|if(var)|ifv return ; " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
return result - > tokAt ( 3 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; alloc|assign|return callfunc| ; " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
return result - > tokAt ( 2 ) ;
}
2010-09-27 17:53:10 +02:00
if ( ( result = Token : : findmatch ( tokens , " ; alloc ; if assign ; " ) ) ! = NULL )
2009-09-01 19:33:17 +02:00
{
2010-09-27 17:53:10 +02:00
return result - > tokAt ( 4 ) ;
2009-09-01 19:33:17 +02:00
}
2010-05-31 18:20:34 +02:00
if ( ( ( result = Token : : findmatch ( tokens , " ; alloc ; if dealloc ; } " ) ) ! = NULL ) & &
! result - > tokAt ( 7 ) )
{
return result - > tokAt ( 6 ) ;
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tokens , " alloc ; } " ) ) ! = NULL )
2009-08-23 15:48:25 +02:00
{
2010-04-02 07:30:58 +02:00
if ( result - > tokAt ( 3 ) = = NULL )
2009-08-23 15:48:25 +02:00
return result - > tokAt ( 2 ) ;
}
// No deallocation / usage => report leak at the last token
2010-04-02 07:30:58 +02:00
if ( ! Token : : findmatch ( tokens , " dealloc|use " ) )
2009-08-23 15:48:25 +02:00
{
const Token * last = tokens ;
2010-04-02 07:30:58 +02:00
while ( last - > next ( ) )
2009-08-23 15:48:25 +02:00
last = last - > next ( ) ;
2009-12-03 19:19:20 +01:00
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
}
return NULL ;
}
2009-06-08 20:20:43 +02:00
2009-01-15 21:34:39 +01:00
// Check for memory leaks for a function variable.
2009-09-10 21:22:57 +02:00
void CheckMemoryLeakInFunction : : checkScope ( const Token * Tok1 , const std : : string & varname , unsigned int varid , bool classmember , unsigned int sz )
2009-01-15 21:34:39 +01:00
{
std : : list < const Token * > callstack ;
AllocType alloctype = No ;
AllocType dealloctype = No ;
const Token * result ;
2010-05-16 19:55:16 +02:00
Token * tok = getcode ( Tok1 , callstack , varid , alloctype , dealloctype , classmember , sz ) ;
2009-08-02 22:30:43 +02:00
//tok->printOut((std::string("Checkmemoryleak: getcode result for: ") + varname).c_str());
2009-01-15 21:34:39 +01:00
// Simplify the code and check if freed memory is used..
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " [;{}] ; " ) )
2009-06-08 20:20:43 +02:00
Token : : eraseTokens ( tok2 , tok2 - > tokAt ( 2 ) ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ( result = Token : : findmatch ( tok , " [;{}] dealloc ; use_ ; " ) ) ! = NULL )
2009-01-15 21:34:39 +01:00
{
2009-05-30 20:30:44 +02:00
deallocuseError ( result - > tokAt ( 3 ) , varname ) ;
2009-01-15 21:34:39 +01:00
}
2009-01-24 19:55:56 +01:00
// Replace "&use" with "use". Replace "use_" with ";"
2010-04-02 07:30:58 +02:00
for ( Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " &use " )
2009-01-15 21:34:39 +01:00
tok2 - > str ( " use " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " use_ " )
2009-01-15 21:34:39 +01:00
tok2 - > str ( " ; " ) ;
2010-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 " ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " realloc " )
2009-01-15 21:34:39 +01:00
{
tok2 - > str ( " dealloc " ) ;
tok2 - > insertToken ( " alloc " ) ;
tok2 - > insertToken ( " ; " ) ;
}
}
2009-10-08 20:49:27 +02:00
// If the variable is not allocated at all => no memory leak
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , " alloc " ) = = 0 )
2009-10-08 20:49:27 +02:00
{
Tokenizer : : deleteTokens ( tok ) ;
return ;
}
2010-05-16 19:55:16 +02:00
simplifycode ( tok ) ;
2009-08-02 21:23:47 +02:00
2010-08-27 20:28:00 +02:00
if ( _settings - > debug & & _settings - > _verbose )
2009-08-02 21:23:47 +02:00
{
2009-08-19 19:42:07 +02:00
tok - > printOut ( ( " Checkmemoryleak: simplifycode result for: " + varname ) . c_str ( ) ) ;
2009-08-02 21:23:47 +02:00
}
2009-01-15 21:34:39 +01:00
// If the variable is not allocated at all => no memory leak
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , " alloc " ) = = 0 )
2009-01-15 21:34:39 +01:00
{
Tokenizer : : deleteTokens ( tok ) ;
return ;
}
2009-07-14 08:17:12 +02:00
/** @todo handle "goto" */
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , " goto " ) )
2009-01-15 21:34:39 +01:00
{
Tokenizer : : deleteTokens ( tok ) ;
return ;
}
2010-05-16 19:55:16 +02:00
if ( ( result = findleak ( tok ) ) ! = NULL )
2009-01-15 21:34:39 +01:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( result , varname , alloctype ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( ( result = Token : : findmatch ( tok , " dealloc ; dealloc ; " ) ) ! = NULL )
2009-01-15 21:34:39 +01:00
{
2009-03-21 17:58:13 +01:00
deallocDeallocError ( result - > tokAt ( 2 ) , varname ) ;
2009-01-15 21:34:39 +01:00
}
// detect cases that "simplifycode" don't handle well..
2010-08-27 20:28:00 +02:00
else if ( _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 ;
2009-05-21 17:55:52 +02:00
noerr | = Token : : simpleMatch ( first , " alloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; dealloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; return use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; use ; return ; } " ) ;
2010-09-11 21:14:20 +02:00
noerr | = Token : : simpleMatch ( first , " alloc ; dealloc ; return ; } " ) ;
2009-05-21 17:55:52 +02:00
noerr | = Token : : simpleMatch ( first , " if alloc ; dealloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " if alloc ; return use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " if alloc ; use ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; ifv return ; dealloc ; } " ) ;
noerr | = Token : : simpleMatch ( first , " alloc ; if return ; dealloc; } " ) ;
2009-01-15 21:34:39 +01:00
// Unhandled case..
2010-04-02 07:30:58 +02:00
if ( ! noerr )
2009-01-15 21:34:39 +01:00
{
2010-08-27 20:28:00 +02:00
std : : ostringstream errmsg ;
2011-01-04 03:40:31 +01:00
errmsg < < " inconclusive leak of " < < varname < < " : " ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2010-08-27 20:28:00 +02:00
errmsg < < " " < < tok2 - > str ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
2009-01-15 21:34:39 +01:00
}
}
Tokenizer : : deleteTokens ( tok ) ;
}
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
2010-05-18 07:46:48 +02:00
//---------------------------------------------------------------------------
// Check for memory leaks due to improper realloc() usage.
// Below, "a" may be set to null without being freed if realloc() cannot
// allocate the requested memory:
2010-05-18 20:08:27 +02:00
// a = malloc(10); a = realloc(a, 100);
2010-05-18 07:46:48 +02:00
//---------------------------------------------------------------------------
void CheckMemoryLeakInFunction : : checkReallocUsage ( )
{
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-08 07:49:01 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2010-05-18 07:46:48 +02:00
{
2010-12-08 07:49:01 +01:00
// only check functions
2011-01-17 18:29:19 +01:00
if ( scope - > type ! = Scope : : eFunction )
2010-12-08 07:49:01 +01:00
continue ;
2010-07-19 08:55:39 +02:00
// Record the varid's of the function parameters
std : : set < unsigned int > parameterVarIds ;
2011-01-17 18:29:19 +01:00
for ( const Token * tok2 = scope - > classDef - > next ( ) ; tok2 & & tok2 - > str ( ) ! = " ) " ; tok2 = tok2 - > next ( ) )
2010-07-19 08:55:39 +02:00
{
2010-08-24 20:50:04 +02:00
if ( tok2 - > varId ( ) ! = 0 )
parameterVarIds . insert ( tok2 - > varId ( ) ) ;
2010-07-19 08:55:39 +02:00
}
2011-01-17 18:29:19 +01:00
const Token * tok = scope - > classStart ;
2010-08-24 20:50:04 +02:00
const Token * startOfFunction = tok ;
2011-10-11 22:07:14 +02:00
// Search for the "var = realloc(var, 100" pattern within this function
2010-12-08 07:49:01 +01:00
unsigned int indentlevel = 1 ;
2010-07-19 08:55:39 +02:00
for ( tok = tok - > next ( ) ; tok ; tok = tok - > next ( ) )
2010-05-18 07:46:48 +02:00
{
2010-07-19 08:55:39 +02:00
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
{
2010-12-08 07:49:01 +01:00
- - indentlevel ;
2010-07-19 08:55:39 +02:00
if ( indentlevel = = 0 )
break ;
}
2010-08-24 20:58:22 +02:00
if ( tok - > varId ( ) > 0 & &
2011-10-11 22:07:14 +02:00
Token : : Match ( tok , " %var% = realloc|g_try_realloc ( %var% , %any% " ) & &
2010-07-19 08:55:39 +02:00
tok - > varId ( ) = = tok - > tokAt ( 4 ) - > varId ( ) & &
parameterVarIds . find ( tok - > varId ( ) ) = = parameterVarIds . end ( ) )
2010-05-18 07:46:48 +02:00
{
2010-07-27 08:17:27 +02:00
// Check that another copy of the pointer wasn't saved earlier in the function
2011-01-13 07:33:46 +01:00
if ( Token : : findmatch ( startOfFunction , " %var% = %varid% ; " , tok - > varId ( ) ) | |
Token : : findmatch ( startOfFunction , " [{};] %varid% = %var% [;=] " , tok - > varId ( ) ) )
continue ;
2011-10-11 22:07:14 +02:00
const Token * tokEndRealloc = tok - > tokAt ( 3 ) - > link ( ) ;
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
2011-10-11 22:07:14 +02:00
if ( Token : : Match ( tokEndRealloc - > tokAt ( 1 ) , " ; if ( ! %varid% ) { " , tok - > varId ( ) ) )
2011-01-13 07:33:46 +01:00
{
2011-10-11 22:07:14 +02:00
const Token * tokEndBrace = tokEndRealloc - > tokAt ( 7 ) - > link ( ) ;
2011-01-13 07:33:46 +01:00
if ( tokEndBrace & & Token : : simpleMatch ( tokEndBrace - > tokAt ( - 2 ) , " ) ; " ) & &
Token : : Match ( tokEndBrace - > tokAt ( - 2 ) - > link ( ) - > tokAt ( - 2 ) , " {|}|; %var% ( " ) )
continue ;
}
memleakUponReallocFailureError ( tok , tok - > str ( ) ) ;
2010-05-18 07:46:48 +02:00
}
2011-10-11 22:07:14 +02:00
else if ( tok - > tokAt ( 1 ) - > varId ( ) > 0 & &
( Token : : Match ( tok , " * %var% = realloc|g_try_realloc ( * %var% , %any% " ) & &
tok - > tokAt ( 1 ) - > varId ( ) = = tok - > tokAt ( 6 ) - > varId ( ) ) & &
parameterVarIds . find ( tok - > tokAt ( 1 ) - > varId ( ) ) = = parameterVarIds . end ( ) )
{
// Check that another copy of the pointer wasn't saved earlier in the function
if ( Token : : findmatch ( startOfFunction , " %var% = * %varid% ; " , tok - > tokAt ( 1 ) - > varId ( ) ) | |
Token : : findmatch ( startOfFunction , " [{};] * %varid% = %var% [;=] " , tok - > tokAt ( 1 ) - > varId ( ) ) )
continue ;
const Token * tokEndRealloc = tok - > tokAt ( 4 ) - > link ( ) ;
// Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
if ( Token : : Match ( tokEndRealloc - > tokAt ( 1 ) , " ; if ( ! * %varid% ) { " , tok - > tokAt ( 1 ) - > varId ( ) ) )
{
const Token * tokEndBrace = tokEndRealloc - > tokAt ( 8 ) - > link ( ) ;
if ( tokEndBrace & & Token : : simpleMatch ( tokEndBrace - > tokAt ( - 2 ) , " ) ; " ) & &
Token : : Match ( tokEndBrace - > tokAt ( - 2 ) - > link ( ) - > tokAt ( - 2 ) , " {|}|; %var% ( " ) )
continue ;
}
memleakUponReallocFailureError ( tok - > tokAt ( 1 ) , tok - > tokAt ( 1 ) - > str ( ) ) ;
}
2010-05-18 07:46:48 +02:00
}
}
}
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
2009-01-15 21:34:39 +01:00
//---------------------------------------------------------------------------
// Checks for memory leaks inside function..
//---------------------------------------------------------------------------
2010-04-24 22:24:03 +02:00
void CheckMemoryLeakInFunction : : parseFunctionScope ( const Token * tok , const Token * tok1 , const bool classmember )
2009-01-15 21:34:39 +01:00
{
2009-12-30 21:29:54 +01:00
// Check locking/unlocking of global resources..
checkScope ( tok - > next ( ) , " " , 0 , classmember , 1 ) ;
2009-11-14 09:06:28 +01:00
2010-04-24 22:24:03 +02:00
// Locate parameters and check their usage..
for ( const Token * tok2 = tok1 ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 = = tok )
break ;
if ( tok2 - > str ( ) = = " ) " )
break ;
if ( Token : : Match ( tok2 , " [(,] %type% * %var% [,)] " ) & & tok2 - > next ( ) - > isStandardType ( ) )
{
const std : : string varname ( tok2 - > strAt ( 3 ) ) ;
const unsigned int varid = tok2 - > tokAt ( 3 ) - > varId ( ) ;
2010-12-16 21:27:33 +01:00
const unsigned int sz = _tokenizer - > sizeOfType ( tok2 - > next ( ) ) ;
2010-04-24 22:24:03 +02:00
checkScope ( tok - > next ( ) , varname , varid , classmember , sz ) ;
}
}
2009-12-30 21:29:54 +01:00
// Locate variable declarations and check their usage..
unsigned int indentlevel = 0 ;
do
2009-01-15 21:34:39 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-15 21:34:39 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-12-30 21:29:54 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 1 )
2009-12-30 21:29:54 +01:00
break ;
2009-01-15 21:34:39 +01:00
- - indentlevel ;
2009-12-30 21:29:54 +01:00
}
2009-01-15 21:34:39 +01:00
2009-07-31 23:42:21 +02:00
// Skip these weird blocks... "( { ... } )"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " ( { " ) )
2009-07-31 23:42:21 +02:00
{
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-07-31 23:42:21 +02:00
break ;
continue ;
}
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " [{};] %type% " ) )
2009-12-30 21:29:54 +01:00
continue ;
2009-01-15 21:34:39 +01:00
2009-12-30 21:29:54 +01:00
// Don't check static/extern variables
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > next ( ) , " static|extern " ) )
2009-12-30 21:29:54 +01:00
continue ;
2009-05-21 21:51:19 +02:00
2009-12-30 21:29:54 +01:00
// return/else is not part of a variable declaration..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > next ( ) , " return|else " ) )
2009-12-30 21:29:54 +01:00
continue ;
2009-03-10 20:44:24 +01:00
2009-12-30 21:29:54 +01:00
unsigned int sz = _tokenizer - > sizeOfType ( tok - > next ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( sz < 1 )
2009-12-30 21:29:54 +01:00
sz = 1 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [{};] %type% * const| %var% [;=] " ) )
2009-12-30 21:29:54 +01:00
{
const Token * vartok = tok - > tokAt ( tok - > tokAt ( 3 ) - > str ( ) ! = " const " ? 3 : 4 ) ;
checkScope ( tok - > next ( ) , vartok - > str ( ) , vartok - > varId ( ) , classmember , sz ) ;
2009-01-15 21:34:39 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [{};] %type% %type% * const| %var% [;=] " ) )
2009-01-15 21:34:39 +01:00
{
2009-12-30 21:29:54 +01:00
const Token * vartok = tok - > tokAt ( tok - > tokAt ( 4 ) - > str ( ) ! = " const " ? 4 : 5 ) ;
checkScope ( tok - > next ( ) , vartok - > str ( ) , vartok - > varId ( ) , classmember , sz ) ;
}
2009-02-07 11:54:39 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [{};] int %var% [;=] " ) )
2009-12-30 21:29:54 +01:00
{
const Token * vartok = tok - > tokAt ( 2 ) ;
checkScope ( tok - > next ( ) , vartok - > str ( ) , vartok - > varId ( ) , classmember , sz ) ;
}
}
2010-04-02 07:30:58 +02:00
while ( 0 ! = ( tok = tok - > next ( ) ) ) ;
2009-12-30 21:29:54 +01:00
}
2009-07-06 12:20:13 +02:00
2009-12-30 21:29:54 +01:00
void CheckMemoryLeakInFunction : : check ( )
{
2010-12-08 07:49:01 +01:00
// fill the "noreturn"
2009-12-30 21:29:54 +01:00
parse_noreturn ( ) ;
2009-07-06 12:20:13 +02:00
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-08 07:49:01 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2009-12-30 21:29:54 +01:00
{
2010-12-08 07:49:01 +01:00
// only check functions
2011-01-17 18:29:19 +01:00
if ( scope - > type ! = Scope : : eFunction )
2009-12-30 21:29:54 +01:00
continue ;
2009-08-29 15:20:37 +02:00
2011-01-17 18:29:19 +01:00
const Token * tok = scope - > classStart ;
const Token * tok1 = scope - > classDef - > next ( ) ;
bool classmember = scope - > functionOf ! = NULL ;
2009-06-21 17:01:43 +02:00
2010-12-08 07:49:01 +01:00
parseFunctionScope ( tok , tok1 , classmember ) ;
2009-01-15 21:34:39 +01:00
}
}
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
2009-01-15 21:34:39 +01:00
//---------------------------------------------------------------------------
// Checks for memory leaks in classes..
//---------------------------------------------------------------------------
2009-06-08 20:20:43 +02:00
void CheckMemoryLeakInClass : : check ( )
2009-01-15 21:34:39 +01:00
{
2011-01-16 18:13:54 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2009-01-15 21:34:39 +01:00
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-05-15 19:40:32 +02:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2009-01-15 21:34:39 +01:00
{
2010-11-23 18:41:07 +01:00
// only check classes and structures
2011-02-04 20:17:25 +01:00
if ( scope - > isClassOrStruct ( ) )
2009-01-15 21:34:39 +01:00
{
2011-01-17 18:29:19 +01:00
std : : list < Variable > : : const_iterator var ;
for ( var = scope - > varlist . begin ( ) ; var ! = scope - > varlist . end ( ) ; + + var )
2010-11-23 18:41:07 +01:00
{
2011-01-18 07:32:06 +01:00
if ( ! var - > isStatic ( ) & & var - > nameToken ( ) - > previous ( ) - > str ( ) = = " * " )
2010-11-23 18:41:07 +01:00
{
// allocation but no deallocation of private variables in public function..
2011-01-18 07:32:06 +01:00
if ( var - > nameToken ( ) - > tokAt ( - 2 ) - > isStandardType ( ) )
2010-11-25 21:04:49 +01:00
{
2011-01-18 07:32:06 +01:00
if ( var - > isPrivate ( ) )
2011-03-11 01:43:29 +01:00
checkPublicFunctions ( & ( * scope ) , var - > nameToken ( ) ) ;
2010-11-25 21:04:49 +01:00
2011-03-11 01:43:29 +01:00
variable ( & ( * scope ) , var - > nameToken ( ) ) ;
2010-11-25 21:04:49 +01:00
}
2010-12-04 07:29:12 +01:00
// known class?
2011-01-18 07:32:06 +01:00
else if ( var - > type ( ) )
2010-11-25 21:04:49 +01:00
{
2011-01-30 08:38:20 +01:00
// not derived?
if ( var - > type ( ) - > derivedFrom . empty ( ) )
2010-12-04 07:29:12 +01:00
{
2011-01-18 07:32:06 +01:00
if ( var - > isPrivate ( ) )
2011-03-11 01:43:29 +01:00
checkPublicFunctions ( & ( * scope ) , var - > nameToken ( ) ) ;
2010-12-04 07:29:12 +01:00
2011-03-11 01:43:29 +01:00
variable ( & ( * scope ) , var - > nameToken ( ) ) ;
2010-12-04 07:29:12 +01:00
}
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
{
2010-01-27 21:02:13 +01:00
const std : : string varname = tokVarname - > strAt ( 0 ) ;
2011-01-17 18:29:19 +01: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 ;
for ( func = scope - > functionList . begin ( ) ; func ! = scope - > functionList . end ( ) ; + + func )
2009-01-15 21:34:39 +01:00
{
2010-11-23 18:41:07 +01:00
const Token * functionToken = func - > token ;
2011-01-17 18:29:19 +01:00
const bool constructor = func - > type = = Function : : eConstructor ;
const bool destructor = func - > type = = Function : : eDestructor ;
2010-01-27 21:02:13 +01:00
unsigned int indent = 0 ;
2009-03-14 20:19:36 +01:00
bool initlist = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = functionToken ; tok ; tok = tok - > next ( ) )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-03-14 18:21:37 +01:00
+ + indent ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent < = 1 )
2009-03-14 18:21:37 +01:00
break ;
2010-01-27 21:02:13 +01:00
- - indent ;
2009-03-14 18:21:37 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( indent = = 0 & & Token : : simpleMatch ( tok , " ) : " ) )
2009-03-14 20:19:36 +01:00
initlist = true ;
2010-04-02 07:30:58 +02:00
else if ( initlist | | indent > 0 )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent = = 0 )
2009-03-14 20:19:36 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , ( " :|, " + varname + " ( " ) . c_str ( ) ) )
2009-03-14 20:19:36 +01:00
continue ;
}
2009-03-14 18:21:37 +01:00
// Allocate..
2010-04-02 07:30:58 +02:00
if ( indent = = 0 | | Token : : Match ( tok , ( varname + " = " ) . c_str ( ) ) )
2009-03-14 18:21:37 +01:00
{
2010-06-13 19:00:11 +02:00
// var1 = var2 = ...
// bail out
if ( Token : : simpleMatch ( tok - > previous ( ) , " = " ) )
return ;
// Foo::var1 = ..
2010-12-07 07:07:36 +01:00
// bail out when not same class
if ( Token : : simpleMatch ( tok - > previous ( ) , " :: " ) & &
2011-01-17 18:29:19 +01:00
tok - > strAt ( - 2 ) ! = scope - > className )
2010-06-13 19:00:11 +02:00
return ;
2009-08-19 19:42:07 +02:00
AllocType alloc = getAllocationType ( tok - > tokAt ( ( indent > 0 ) ? 2 : 3 ) , 0 ) ;
2010-04-02 07:30:58 +02:00
if ( alloc ! = CheckMemoryLeak : : No )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( constructor )
2009-10-23 20:04:47 +02:00
allocInConstructor = true ;
2010-04-02 07:30:58 +02:00
if ( Alloc ! = No & & Alloc ! = alloc )
2009-06-08 20:20:43 +02:00
alloc = CheckMemoryLeak : : Many ;
2009-01-15 21:34:39 +01:00
2009-03-14 18:21:37 +01:00
std : : list < const Token * > callstack ;
2010-04-02 07:30:58 +02:00
if ( alloc ! = CheckMemoryLeak : : Many & & Dealloc ! = CheckMemoryLeak : : No & & Dealloc ! = CheckMemoryLeak : : Many & & Dealloc ! = alloc )
2009-03-14 18:21:37 +01:00
{
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , classname + " :: " + varname ) ;
2009-03-14 18:21:37 +01:00
callstack . pop_back ( ) ;
}
2009-01-15 21:34:39 +01:00
2009-03-14 18:21:37 +01:00
Alloc = alloc ;
}
}
2009-01-15 21:34:39 +01:00
2010-04-02 07:30:58 +02:00
if ( indent = = 0 )
2009-03-14 20:19:36 +01:00
continue ;
2009-03-14 18:21:37 +01:00
// Deallocate..
2010-12-07 07:07:36 +01:00
AllocType dealloc = getDeallocationType ( tok , varname ) ;
2010-04-02 07:30:58 +02:00
if ( dealloc = = No )
2009-01-15 21:34:39 +01:00
{
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 ) ;
}
if ( dealloc = = No )
{
std : : string temp = " this . " + varname ;
dealloc = getDeallocationType ( tok , temp ) ;
2009-03-14 18:21:37 +01:00
}
2010-04-02 07:30:58 +02:00
if ( dealloc ! = CheckMemoryLeak : : No )
2009-03-14 18:21:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( destructor )
2009-10-23 20:04:47 +02:00
deallocInDestructor = true ;
2010-01-27 21:02:13 +01:00
// several types of allocation/deallocation?
2010-04-02 07:30:58 +02:00
if ( Dealloc ! = CheckMemoryLeak : : No & & Dealloc ! = dealloc )
2009-06-08 20:20:43 +02:00
dealloc = CheckMemoryLeak : : Many ;
2009-02-06 07:11:47 +01:00
2009-01-15 21:34:39 +01:00
std : : list < const Token * > callstack ;
2010-04-02 07:30:58 +02:00
if ( dealloc ! = CheckMemoryLeak : : Many & & Alloc ! = CheckMemoryLeak : : No & & Alloc ! = Many & & Alloc ! = dealloc )
2009-02-01 16:47:36 +01:00
{
callstack . push_back ( tok ) ;
2010-05-16 19:55:16 +02:00
mismatchAllocDealloc ( callstack , classname + " :: " + varname ) ;
2009-02-01 16:47:36 +01:00
callstack . pop_back ( ) ;
}
2009-02-06 07:11:47 +01:00
2009-03-14 18:21:37 +01:00
Dealloc = dealloc ;
2009-01-15 21:34:39 +01:00
}
2009-10-24 15:07:14 +02:00
2010-06-16 19:28:47 +02:00
// Function call .. possible deallocation
else if ( Token : : Match ( tok - > previous ( ) , " [ { } ; ] % var % ( " ))
2009-10-24 15:07:14 +02:00
{
2011-07-30 13:10:44 +02:00
if ( ! CheckMemoryLeakInFunction : : test_white_list ( tok - > str ( ) . c_str ( ) ) )
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
}
}
2010-04-02 07:30:58 +02:00
if ( allocInConstructor & & ! deallocInDestructor )
2009-10-23 20:04:47 +02:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tokVarname , ( classname + " :: " + varname ) . c_str ( ) , Alloc ) ;
2009-10-23 20:04:47 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Alloc ! = CheckMemoryLeak : : No & & Dealloc = = CheckMemoryLeak : : No )
2009-01-15 21:34:39 +01:00
{
2010-05-16 19:55:16 +02:00
memoryLeak ( tokVarname , ( classname + " :: " + varname ) . c_str ( ) , Alloc ) ;
2009-01-15 21:34:39 +01:00
}
}
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.
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
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 ( ) ;
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-01-17 18:29:19 +01:00
for ( func = scope - > functionList . begin ( ) ; func ! = scope - > functionList . end ( ) ; + + func )
2010-11-25 21:04:49 +01:00
{
2011-01-17 18:29:19 +01:00
if ( func - > type ! = Function : : eConstructor & &
2011-01-17 07:21:59 +01:00
func - > access = = Public & & func - > hasBody )
2010-05-15 19:40:32 +02:00
{
2010-11-25 21:04:49 +01:00
const Token * tok2 = func - > token ;
while ( tok2 - > str ( ) ! = " { " )
tok2 = tok2 - > next ( ) ;
2010-12-05 20:26:52 +01:00
if ( Token : : Match ( tok2 , " {|}|; %varid% = " , varid ) )
2010-11-25 21:04:49 +01:00
{
const CheckMemoryLeak : : AllocType alloc = getAllocationType ( tok2 - > tokAt ( 3 ) , varid ) ;
if ( alloc ! = CheckMemoryLeak : : No )
publicAllocationError ( tok2 , tok2 - > strAt ( 1 ) ) ;
2010-05-15 19:40:32 +02:00
}
2010-12-07 07:07:36 +01:00
else if ( Token : : Match ( tok2 , " {|}|; %type% :: %varid% = " , varid ) & &
2011-01-17 18:29:19 +01:00
tok2 - > next ( ) - > str ( ) = = scope - > className )
2010-12-07 07:07:36 +01:00
{
const CheckMemoryLeak : : AllocType alloc = getAllocationType ( tok2 - > tokAt ( 5 ) , varid ) ;
if ( alloc ! = CheckMemoryLeak : : No )
publicAllocationError ( tok2 , tok2 - > strAt ( 3 ) ) ;
}
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
{
unsigned int indentlevel1 = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel1 ;
else if ( tok - > str ( ) = = " } " )
- - indentlevel1 ;
if ( indentlevel1 = = 0 )
continue ;
// check struct variables..
if ( Token : : Match ( tok , " struct|;|{|} %type% * %var% [=;] " ) )
{
checkStructVariable ( tok - > tokAt ( 3 ) ) ;
}
else if ( Token : : Match ( tok , " struct|;|{|} %type% %var% ; " ) )
{
checkStructVariable ( tok - > tokAt ( 2 ) ) ;
}
}
}
bool CheckMemoryLeakStructMember : : isMalloc ( const Token * vartok )
{
const unsigned int varid ( vartok - > varId ( ) ) ;
bool alloc = false ;
unsigned int indentlevel2 = 0 ;
for ( const Token * tok2 = vartok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
else if ( tok2 - > str ( ) = = " } " )
{
if ( indentlevel2 = = 0 )
break ;
- - indentlevel2 ;
}
else if ( Token : : Match ( tok2 , " = %varid% [;=] " , varid ) )
{
return false ;
}
else if ( Token : : Match ( tok2 , " %varid% = malloc|kmalloc ( " , varid ) )
{
alloc = true ;
}
}
return alloc ;
}
void CheckMemoryLeakStructMember : : checkStructVariable ( const Token * const vartok )
2009-07-19 16:51:31 +02:00
{
2009-07-22 08:30:51 +02:00
// This should be in the CheckMemoryLeak base class
std : : set < std : : string > ignoredFunctions ;
ignoredFunctions . insert ( " if " ) ;
ignoredFunctions . insert ( " for " ) ;
ignoredFunctions . insert ( " while " ) ;
ignoredFunctions . insert ( " malloc " ) ;
2011-05-11 18:19:14 +02:00
if ( vartok - > varId ( ) = = 0 )
return ;
2009-09-28 22:58:06 +02:00
2011-05-11 18:19:14 +02:00
// Is struct variable a pointer?
if ( vartok - > strAt ( - 1 ) = = " * " )
2009-07-19 16:51:31 +02:00
{
2011-05-11 18:19:14 +02:00
// Check that variable is allocated with malloc
if ( ! isMalloc ( vartok ) )
return ;
}
else
{
// If file extension is not .c then a destructor might cleanup
// members
const std : : string & fname = _tokenizer - > getFiles ( ) - > at ( 0 ) ;
if ( fname . find ( " .c " ) ! = fname . size ( ) - 2U )
return ;
}
2009-09-28 22:58:06 +02:00
2011-05-11 18:19:14 +02:00
// Check struct..
unsigned int indentlevel2 = 0 ;
for ( const Token * tok2 = vartok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
else if ( tok2 - > str ( ) = = " } " )
2009-07-19 16:51:31 +02:00
{
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 */
else if ( Token : : Match ( tok2 , " [(,] %varid% [,)] " , vartok - > varId ( ) ) )
break ;
// Struct member is allocated => check if it is also properly deallocated..
else if ( Token : : Match ( tok2 - > previous ( ) , " [ ; { } ] % varid % . % var % = malloc | strdup | kmalloc ( " , vartok->varId()))
{
const unsigned int structid ( vartok - > varId ( ) ) ;
const unsigned int structmemberid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
// This struct member is allocated.. check that it is deallocated
unsigned int indentlevel3 = indentlevel2 ;
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > next ( ) )
2009-07-19 16:51:31 +02:00
{
2011-05-11 18:19:14 +02:00
if ( tok3 - > str ( ) = = " { " )
+ + indentlevel3 ;
else if ( tok3 - > str ( ) = = " } " )
2009-07-19 16:51:31 +02:00
{
2011-05-11 18:19:14 +02:00
if ( indentlevel3 = = 0 )
2009-07-19 16:51:31 +02:00
{
2011-05-11 18:19:14 +02:00
memoryLeak ( tok3 , ( vartok - > str ( ) + " . " + tok2 - > strAt ( 2 ) ) . c_str ( ) , 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..
else if ( Token : : Match ( tok3 , " free|kfree ( %var% . %varid% ) " , structmemberid ) )
2009-07-19 16:51:31 +02:00
{
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 ;
while ( tok3 )
{
// debug info
const std : : string tok3str_ ( tok3 - > str ( ) ) ;
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..
else if ( indentlevel2 = = 0 & & Token : : Match ( tok3 , " free|kfree ( %varid% ) " , structid ) )
{
memoryLeak ( tok3 , ( vartok - > str ( ) + " . " + tok2 - > strAt ( 2 ) ) . c_str ( ) , 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..
else if ( Token : : Match ( tok3 , " if ( ! %var% . %varid% ) " , structmemberid ) )
2009-07-19 16:51:31 +02: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
// 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
else if ( Token : : Match ( tok3 , " if ( %var% . %varid% ) { " , structmemberid))
{
// 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 ;
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
{
if ( tok4 - > str ( ) = = " { " )
+ + indentlevel4 ;
else if ( tok4 - > str ( ) = = " } " )
{
- - indentlevel4 ;
if ( indentlevel4 = = 0 )
2009-07-20 14:39:24 +02:00
break ;
}
2011-05-11 18:19:14 +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..
else if ( tok3 - > str ( ) = = " return " )
{
// Returning from function without deallocating struct member?
if ( ! Token : : Match ( tok3 , " return %varid% ; " , structid ) & &
! Token : : Match ( tok3 , " return & %varid% . " , structid ) )
{
memoryLeak ( tok3 , ( vartok - > str ( ) + " . " + tok2 - > strAt ( 2 ) ) . c_str ( ) , Malloc ) ;
}
break ;
}
2009-08-17 22:23:37 +02:00
2011-08-08 19:58:25 +02:00
// struct assignment..
else if ( Token : : Match ( tok3 , " = %varid% ; " , structid ) )
{
break ;
}
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..
else if ( Token : : Match ( tok3 , " %var% ( " ) )
{
// 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 ;
unsigned int parlevel = 0 ;
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
{
if ( tok4 - > str ( ) = = " ( " )
+ + parlevel ;
2009-09-28 22:41:45 +02:00
2011-05-11 18:19:14 +02:00
else if ( tok4 - > str ( ) = = " ) " )
{
if ( parlevel < = 1 )
2009-09-28 22:41:45 +02:00
break ;
2011-05-11 18:19:14 +02:00
- - parlevel ;
2009-09-28 22:41:45 +02:00
}
2011-07-21 13:33:20 +02:00
if ( Token : : Match ( tok4 , " [(,] &| %varid% [,)] " , structid ) )
2009-07-19 16:51:31 +02:00
{
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
2011-08-26 19:26:21 +02:00
if ( Token : : Match ( tok4 , " [(,] &| %varid% . %var% [,)] " , 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
# include "checkuninitvar.h" // CheckUninitVar::analyse
void CheckMemoryLeakNoVar : : check ( )
{
std : : set < std : : string > uvarFunctions ;
{
const CheckUninitVar c ( _tokenizer , _settings , _errorLogger ) ;
c . analyse ( _tokenizer - > tokens ( ) , uvarFunctions ) ;
}
2011-01-16 18:13:54 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-12-09 06:15:01 +01:00
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-09 06:15:01 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2010-11-12 21:09:34 +01:00
{
2010-12-09 06:15:01 +01:00
// only check functions
2011-01-17 18:29:19 +01:00
if ( scope - > type ! = Scope : : eFunction )
2010-12-09 06:15:01 +01:00
continue ;
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...
for ( const Token * tok2 = tok - > link ( ) ; tok2 & & tok2 ! = tok ; tok2 = tok2 - > next ( ) )
{
// allocating memory in parameter for function call..
if ( Token : : Match ( tok2 , " [(,] %var% ( " ) & & Token : : Match ( tok2 - > tokAt ( 2 ) - > link ( ) , " ) [,)] " ) )
{
const AllocType allocType = getAllocationType ( tok2 - > next ( ) , 0 ) ;
if ( allocType ! = No )
{
// locate outer function call..
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > previous ( ) )
{
if ( tok3 - > str ( ) = = " ( " )
{
// Is it a function call..
if ( Token : : Match ( tok3 - > tokAt ( - 2 ) , " [(,;{}] %var% ( " ) )
{
const std : : string functionName = tok3 - > strAt ( - 1 ) ;
2011-01-02 08:32:51 +01:00
if ( functionName = = " delete " | |
functionName = = " free " | |
functionName = = " fclose " | |
functionName = = " realloc " )
break ;
2010-11-12 21:09:34 +01:00
if ( CheckMemoryLeakInFunction : : test_white_list ( functionName ) )
{
functionCallLeak ( tok2 , tok2 - > strAt ( 1 ) , functionName ) ;
break ;
}
if ( uvarFunctions . find ( functionName ) ! = uvarFunctions . end ( ) )
{
functionCallLeak ( tok2 , tok2 - > strAt ( 1 ) , functionName ) ;
break ;
}
}
break ;
}
else if ( tok3 - > str ( ) = = " ) " )
tok3 = tok3 - > link ( ) ;
else if ( Token : : Match ( tok3 , " [;{}] " ) )
break ;
}
}
}
}
}
}
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. " ) ;
}