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