2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-01-31 20:29:27 +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-31 20:29:27 +01:00
*/
//---------------------------------------------------------------------------
// Buffer overrun..
//---------------------------------------------------------------------------
# include "checkbufferoverrun.h"
2009-02-11 06:16:10 +01:00
# include "tokenize.h"
# include "errorlogger.h"
2009-08-02 14:26:26 +02:00
# include "mathlib.h"
2009-02-11 06:16:10 +01:00
2009-01-31 20:29:27 +01:00
# include <algorithm>
# include <sstream>
# include <list>
# include <cstring>
2009-09-20 12:54:19 +02:00
# include <cctype>
2009-01-31 20:29:27 +01:00
2009-09-27 16:09:41 +02:00
# include <cassert> // <- assert
2009-01-31 20:29:27 +01:00
# include <cstdlib> // <- strtoul
//---------------------------------------------------------------------------
2009-03-20 18:16:21 +01:00
// Register this check class (by creating a static instance of it)
namespace
{
2009-07-13 16:00:15 +02:00
CheckBufferOverrun instance ;
2009-03-20 18:16:21 +01:00
}
//---------------------------------------------------------------------------
2009-01-31 20:29:27 +01:00
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const Token * tok )
2009-01-31 20:29:27 +01:00
{
2009-08-04 21:36:55 +02:00
if ( ! tok )
arrayIndexOutOfBounds ( ) ;
else
{
_callStack . push_back ( tok ) ;
arrayIndexOutOfBounds ( ) ;
_callStack . pop_back ( ) ;
}
2009-01-31 20:29:27 +01:00
}
2009-03-21 21:33:27 +01:00
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( )
2009-03-21 21:33:27 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( _callStack , Severity : : possibleError , " arrayIndexOutOfBounds " , " Array index out of bounds " ) ;
2009-03-21 21:33:27 +01:00
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : bufferOverrun ( const Token * tok )
2009-03-21 21:33:27 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : possibleError , " bufferOverrun " , " Buffer overrun " ) ;
2009-03-21 21:33:27 +01:00
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : strncatUsage ( const Token * tok )
2009-03-21 21:33:27 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : possibleError , " strncatUsage " , " Dangerous usage of strncat. Tip: the 3rd parameter means maximum number of characters to append " ) ;
2009-03-21 21:33:27 +01:00
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : outOfBounds ( const Token * tok , const std : : string & what )
2009-03-21 21:33:27 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " outOfBounds " , what + " is out of bounds " ) ;
2009-03-21 21:33:27 +01:00
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : sizeArgumentAsChar ( const Token * tok )
2009-03-25 07:25:10 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : possibleError , " sizeArgumentAsChar " , " The size argument is given as a char constant " ) ;
2009-03-25 07:25:10 +01:00
}
2009-01-31 20:29:27 +01:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check array usage..
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : checkScope ( const Token * tok , const char * varname [ ] , const int size , const int total_size , unsigned int varid )
2009-01-31 20:29:27 +01:00
{
unsigned int varc = 0 ;
std : : string varnames ;
while ( varname [ varc ] )
{
if ( varc > 0 )
varnames + = " . " ;
varnames + = varname [ varc ] ;
+ + varc ;
}
if ( varc = = 0 )
varc = 1 ;
varc = 2 * ( varc - 1 ) ;
// Array index..
if ( varid > 0 )
{
if ( Token : : Match ( tok , " %varid% [ %num% ] " , varid ) )
{
const char * num = tok - > strAt ( 2 ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-02-01 16:47:36 +01:00
arrayIndexOutOfBounds ( tok - > next ( ) ) ;
2009-01-31 20:29:27 +01:00
}
}
}
else if ( Token : : Match ( tok , std : : string ( varnames + " [ %num% ] " ) . c_str ( ) ) )
{
const char * num = tok - > strAt ( 2 + varc ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-02-01 16:47:36 +01:00
arrayIndexOutOfBounds ( tok - > next ( ) ) ;
2009-01-31 20:29:27 +01:00
}
}
int indentlevel = 0 ;
for ( ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < 0 )
return ;
}
// Array index..
if ( varid > 0 )
{
if ( ! tok - > isName ( ) & & ! Token : : Match ( tok , " [.&] " ) & & Token : : Match ( tok - > next ( ) , " %varid% [ %num% ] " , varid ) )
{
const char * num = tok - > strAt ( 3 ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-02-01 16:47:36 +01:00
arrayIndexOutOfBounds ( tok - > next ( ) ) ;
2009-01-31 20:29:27 +01:00
}
}
}
else if ( ! tok - > isName ( ) & & ! Token : : Match ( tok , " [.&] " ) & & Token : : Match ( tok - > next ( ) , std : : string ( varnames + " [ %num% ] " ) . c_str ( ) ) )
{
const char * num = tok - > next ( ) - > strAt ( 2 + varc ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-02-01 16:47:36 +01:00
arrayIndexOutOfBounds ( tok - > next ( ) ) ;
2009-01-31 20:29:27 +01:00
}
tok = tok - > tokAt ( 4 ) ;
continue ;
}
// memset, memcmp, memcpy, strncpy, fgets..
if ( varid > 0 )
{
2009-09-25 22:32:18 +02:00
if ( Token : : Match ( tok , " memset|memcpy|memmove|memcmp|strncpy|fgets ( %varid% , %any% , %any% ) " , varid ) | |
Token : : Match ( tok , " memset|memcpy|memmove|memcmp|fgets ( %var% , %varid% , %any% ) " , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
const Token * tokSz = tok - > tokAt ( 6 ) ;
if ( tokSz - > str ( ) [ 0 ] = = ' \' ' )
sizeArgumentAsChar ( tok ) ;
else if ( tokSz - > isNumber ( ) )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
const char * num = tok - > strAt ( 6 ) ;
if ( std : : atoi ( num ) > total_size )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
bufferOverrun ( tok ) ;
2009-01-31 20:29:27 +01:00
}
}
}
}
else if ( Token : : Match ( tok , " memset|memcpy|memmove|memcmp|strncpy|fgets " ) )
{
if ( Token : : Match ( tok - > next ( ) , std : : string ( " ( " + varnames + " , %num% , %num% ) " ) . c_str ( ) ) | |
Token : : Match ( tok - > next ( ) , std : : string ( " ( %var% , " + varnames + " , %num% ) " ) . c_str ( ) ) )
{
const char * num = tok - > strAt ( varc + 6 ) ;
if ( std : : atoi ( num ) > total_size )
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok ) ;
2009-01-31 20:29:27 +01:00
}
}
continue ;
}
// Loop..
if ( Token : : simpleMatch ( tok , " for ( " ) )
{
const Token * tok2 = tok - > tokAt ( 2 ) ;
2009-08-02 14:26:26 +02:00
unsigned int counter_varid = 0 ;
std : : string min_counter_value ;
std : : string max_counter_value ;
2009-01-31 20:29:27 +01:00
// for - setup..
2009-04-04 20:05:48 +02:00
if ( Token : : Match ( tok2 , " %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
if ( tok2 - > tokAt ( 2 ) - > isNumber ( ) )
{
min_counter_value = tok2 - > strAt ( 2 ) ;
}
counter_varid = tok2 - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-08-02 14:26:26 +02:00
}
2009-04-04 20:05:48 +02:00
else if ( Token : : Match ( tok2 , " %type% %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
if ( tok2 - > tokAt ( 3 ) - > isNumber ( ) )
{
min_counter_value = tok2 - > strAt ( 3 ) ;
}
counter_varid = tok2 - > next ( ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 5 ) ;
2009-08-02 14:26:26 +02:00
}
2009-04-04 20:05:48 +02:00
else if ( Token : : Match ( tok2 , " %type% %type% %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
if ( tok - > tokAt ( 4 ) - > isNumber ( ) )
{
min_counter_value = tok2 - > strAt ( 4 ) ;
}
counter_varid = tok2 - > tokAt ( 2 ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 6 ) ;
2009-08-02 14:26:26 +02:00
}
2009-01-31 20:29:27 +01:00
else
continue ;
2009-09-27 16:09:41 +02:00
int value = 0 ;
2009-08-08 20:09:45 +02:00
if ( counter_varid )
2009-08-02 14:26:26 +02:00
{
2009-08-08 20:09:45 +02:00
if ( Token : : Match ( tok2 , " %varid% < %num% ; " , counter_varid ) )
{
2009-09-27 16:09:41 +02:00
value = std : : atoi ( tok2 - > strAt ( 2 ) ) ;
max_counter_value = MathLib : : toString < long > ( value - 1 ) ;
2009-08-08 20:09:45 +02:00
}
else if ( Token : : Match ( tok2 , " %varid% <= %num% ; " , counter_varid ) )
{
2009-09-27 16:09:41 +02:00
value = std : : atoi ( tok2 - > strAt ( 2 ) ) ;
2009-08-08 20:09:45 +02:00
max_counter_value = tok2 - > strAt ( 2 ) ;
}
2009-08-02 14:26:26 +02:00
}
2009-01-31 20:29:27 +01:00
// Get index variable and stopsize.
2009-05-03 20:10:59 +02:00
const char * strindex = tok2 - > str ( ) . c_str ( ) ;
2009-08-02 15:34:28 +02:00
bool condition_out_of_bounds = true ;
2009-09-27 16:09:41 +02:00
if ( value < size )
2009-09-27 17:11:57 +02:00
condition_out_of_bounds = false ;
2009-01-31 20:29:27 +01:00
2009-09-27 16:09:41 +02:00
const Token * tok3 = tok2 - > tokAt ( 4 ) ;
assert ( tok3 ! = NULL ) ;
if ( Token : : Match ( tok3 , " %varid% += %num% ) " , counter_varid ) | |
Token : : Match ( tok3 , " %varid% = %num% + %varid% ) " , counter_varid ) )
{
const int num = std : : atoi ( tok3 - > strAt ( 2 ) ) ;
if ( num > value )
condition_out_of_bounds = false ;
}
else if ( Token : : Match ( tok3 , " %varid% = %varid% + %num% ) " , counter_varid ) )
{
const int num = std : : atoi ( tok3 - > strAt ( 4 ) ) ;
if ( num > value )
condition_out_of_bounds = false ;
}
2009-09-27 17:07:54 +02:00
else if ( ! Token : : Match ( tok3 , " ++| %varid% ++| ) " , counter_varid ) )
{
continue ;
}
2009-09-27 16:09:41 +02:00
2009-08-17 22:23:37 +02:00
// Goto the end paranthesis of the for-statement: "for (x; y; z)" ..
tok2 = tok - > next ( ) - > link ( ) ;
2009-01-31 20:29:27 +01:00
if ( ! tok2 | | ! tok2 - > tokAt ( 5 ) )
break ;
std : : ostringstream pattern ;
pattern < < varnames < < " [ " < < strindex < < " ] " ;
int indentlevel2 = 0 ;
2009-09-13 09:03:48 +02:00
while ( ( tok2 = tok2 - > next ( ) ) ! = 0 )
2009-01-31 20:29:27 +01:00
{
if ( tok2 - > str ( ) = = " ; " & & indentlevel2 = = 0 )
break ;
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
if ( tok2 - > str ( ) = = " } " )
{
- - indentlevel2 ;
if ( indentlevel2 < = 0 )
break ;
}
2009-06-29 23:42:46 +02:00
if ( tok2 - > str ( ) = = " if " )
{
// Bailout
break ;
}
2009-08-02 15:34:28 +02:00
if ( Token : : Match ( tok2 , pattern . str ( ) . c_str ( ) ) & & condition_out_of_bounds )
2009-01-31 20:29:27 +01:00
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok2 ) ;
2009-01-31 20:29:27 +01:00
break ;
}
2009-08-02 15:01:59 +02:00
else if ( varid > 0 & & counter_varid > 0 & & ! min_counter_value . empty ( ) & & ! max_counter_value . empty ( ) )
2009-08-02 14:26:26 +02:00
{
int min_index = 0 ;
int max_index = 0 ;
if ( Token : : Match ( tok2 , " %varid% [ %var% +|-|*|/ %num% ] " , varid ) & &
tok2 - > tokAt ( 2 ) - > varId ( ) = = counter_varid )
{
char action = * ( tok2 - > strAt ( 3 ) ) ;
const std : : string & second ( tok2 - > tokAt ( 4 ) - > str ( ) ) ;
//printf("min_index: %s %c %s\n", min_counter_value.c_str(), action, second.c_str());
//printf("max_index: %s %c %s\n", max_counter_value.c_str(), action, second.c_str());
2009-08-13 22:13:52 +02:00
min_index = std : : atoi ( MathLib : : calculate ( min_counter_value , second , action ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( max_counter_value , second , action ) . c_str ( ) ) ;
2009-08-02 14:26:26 +02:00
}
else if ( Token : : Match ( tok2 , " %varid% [ %num% +|-|*|/ %var% ] " , varid ) & &
tok2 - > tokAt ( 4 ) - > varId ( ) = = counter_varid )
{
char action = * ( tok2 - > strAt ( 3 ) ) ;
const std : : string & first ( tok2 - > tokAt ( 2 ) - > str ( ) ) ;
//printf("min_index: %s %c %s\n", first.c_str(), action, min_counter_value.c_str());
//printf("max_index: %s %c %s\n", first.c_str(), action, max_counter_value.c_str());
2009-08-13 22:13:52 +02:00
min_index = std : : atoi ( MathLib : : calculate ( first , min_counter_value , action ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( first , max_counter_value , action ) . c_str ( ) ) ;
2009-08-02 14:26:26 +02:00
}
//printf("min_index = %d, max_index = %d, size = %d\n", min_index, max_index, size);
if ( min_index > = size | | max_index > = size )
{
arrayIndexOutOfBounds ( tok2 - > next ( ) ) ;
}
}
2009-01-31 20:29:27 +01:00
}
continue ;
}
// Writing data into array..
2009-02-20 22:00:59 +01:00
if ( Token : : Match ( tok , ( " strcpy|strcat ( " + varnames + " , %str% ) " ) . c_str ( ) ) )
2009-01-31 20:29:27 +01:00
{
2009-08-30 13:21:42 +02:00
size_t len = Token : : getStrLength ( tok - > tokAt ( varc + 4 ) ) ;
if ( len > = static_cast < size_t > ( size ) )
2009-01-31 20:29:27 +01:00
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok ) ;
2009-08-30 13:44:23 +02:00
continue ;
2009-01-31 20:29:27 +01:00
}
}
2009-02-20 22:16:07 +01:00
2009-02-20 22:00:59 +01:00
// Dangerous usage of strncat..
2009-03-05 18:28:59 +01:00
if ( varid > 0 & & Token : : Match ( tok , " strncat ( %varid% , %any% , %num% ) " , varid ) )
2009-02-20 22:00:59 +01:00
{
2009-08-13 22:13:52 +02:00
int n = std : : atoi ( tok - > strAt ( 6 ) ) ;
2009-07-11 12:16:38 +02:00
if ( n > = ( size - 1 ) )
2009-03-21 21:33:27 +01:00
strncatUsage ( tok ) ;
2009-02-20 22:00:59 +01:00
}
2009-02-20 22:16:07 +01:00
// Dangerous usage of strncpy + strncat..
2009-03-05 18:28:59 +01:00
if ( varid > 0 & & Token : : Match ( tok , " strncpy|strncat ( %varid% , %any% , %num% ) ; strncat ( %varid% , %any% , %num% ) " , varid ) )
2009-02-20 22:16:07 +01:00
{
2009-08-13 22:13:52 +02:00
int n = std : : atoi ( tok - > strAt ( 6 ) ) + std : : atoi ( tok - > strAt ( 15 ) ) ;
2009-02-20 22:16:07 +01:00
if ( n > size )
2009-03-21 21:33:27 +01:00
strncatUsage ( tok - > tokAt ( 9 ) ) ;
2009-02-20 22:16:07 +01:00
}
2009-08-30 13:44:23 +02:00
// Detect few strcat() calls
if ( varid > 0 & & Token : : Match ( tok , " strcat ( %varid% , %str% ) ; " , varid ) )
{
size_t charactersAppend = 0 ;
const Token * tok2 = tok ;
while ( tok2 & & Token : : Match ( tok2 , " strcat ( %varid% , %str% ) ; " , varid ) )
{
charactersAppend + = Token : : getStrLength ( tok2 - > tokAt ( 4 ) ) ;
if ( charactersAppend > = static_cast < size_t > ( size ) )
{
bufferOverrun ( tok2 ) ;
break ;
}
tok2 = tok2 - > tokAt ( 7 ) ;
}
}
2009-01-31 20:29:27 +01:00
// sprintf..
2009-08-08 16:52:35 +02:00
if ( varid > 0 & & Token : : Match ( tok , " sprintf ( %varid% , %str% [,)] " , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-08-08 16:52:35 +02:00
int len = - 2 ;
2009-08-08 16:03:10 +02:00
2009-08-08 16:52:35 +02:00
// check format string
const char * fmt = tok - > strAt ( 4 ) ;
while ( * fmt )
{
if ( * fmt = = ' \\ ' )
{
+ + fmt ;
}
else if ( * fmt = = ' % ' )
{
2009-09-20 12:54:19 +02:00
+ + fmt ;
// skip field width
2009-09-20 21:42:43 +02:00
while ( std : : isdigit ( * fmt ) )
{
2009-09-20 12:54:19 +02:00
+ + fmt ;
}
2009-08-08 16:52:35 +02:00
// FIXME: better handling for format specifiers
2009-09-20 12:54:19 +02:00
+ + fmt ;
2009-08-08 16:52:35 +02:00
continue ;
}
+ + fmt ;
+ + len ;
}
if ( len > = ( int ) size )
{
bufferOverrun ( tok ) ;
}
2009-08-26 19:17:32 +02:00
// check arguments (if they exists)
if ( tok - > tokAt ( 5 ) - > str ( ) = = " , " )
2009-01-31 20:29:27 +01:00
{
2009-08-26 19:17:32 +02:00
len = 0 ;
const Token * end = tok - > next ( ) - > link ( ) ;
2009-09-26 19:06:54 +02:00
bool argumentAlreadyChecked = false ;
2009-09-26 19:40:58 +02:00
int lastCheckedArgumentMaxSize = 0 ;
2009-08-26 19:17:32 +02:00
for ( const Token * tok2 = tok - > tokAt ( 6 ) ; tok2 & & tok2 ! = end ; tok2 = tok2 - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2009-09-26 19:06:54 +02:00
if ( tok2 - > str ( ) = = " , " )
{
argumentAlreadyChecked = false ;
2009-09-26 19:40:58 +02:00
lastCheckedArgumentMaxSize = 0 ;
2009-09-26 19:06:54 +02:00
}
2009-09-26 19:40:58 +02:00
else if ( Token : : Match ( tok2 , " %str% " ) )
2009-01-31 20:29:27 +01:00
{
2009-09-26 19:40:58 +02:00
int argumentSize = static_cast < int > ( Token : : getStrLength ( tok2 ) ) ;
if ( argumentAlreadyChecked = = false )
{
lastCheckedArgumentMaxSize = argumentSize ;
len + = argumentSize ;
argumentAlreadyChecked = true ;
}
else if ( argumentSize > lastCheckedArgumentMaxSize )
{
// when sprintf() argument is ternary
// operation we may have two and more
// strings as argument. In this case we
// use length of longest string.
len + = ( argumentSize - lastCheckedArgumentMaxSize ) ;
lastCheckedArgumentMaxSize = argumentSize ;
}
2009-01-31 20:29:27 +01:00
}
}
2009-08-26 19:17:32 +02:00
if ( len > = ( int ) size )
{
bufferOverrun ( tok ) ;
}
2009-01-31 20:29:27 +01:00
}
}
// snprintf..
2009-03-24 18:43:39 +01:00
if ( varid > 0 & & Token : : Match ( tok , " snprintf ( %varid% , %num% , " , varid ) )
2009-01-31 20:29:27 +01:00
{
int n = std : : atoi ( tok - > strAt ( 4 ) ) ;
if ( n > size )
2009-03-21 21:33:27 +01:00
outOfBounds ( tok - > tokAt ( 4 ) , " snprintf size " ) ;
2009-01-31 20:29:27 +01:00
}
2009-02-21 13:22:04 +01:00
// cin..
if ( varid > 0 & & Token : : Match ( tok , " cin >> %varid% ; " , varid ) )
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok ) ;
2009-02-21 13:22:04 +01:00
}
2009-01-31 20:29:27 +01:00
// Function call..
// It's not interesting to check what happens when the whole struct is
// sent as the parameter, that is checked separately anyway.
if ( Token : : Match ( tok , " %var% ( " ) )
{
// Don't make recursive checking..
if ( std : : find ( _callStack . begin ( ) , _callStack . end ( ) , tok ) ! = _callStack . end ( ) )
continue ;
// Only perform this checking if showAll setting is enabled..
2009-03-20 17:35:53 +01:00
if ( ! _settings - > _showAll )
2009-01-31 20:29:27 +01:00
continue ;
unsigned int parlevel = 0 , par = 0 ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
{
+ + parlevel ;
}
else if ( tok2 - > str ( ) = = " ) " )
{
- - parlevel ;
if ( parlevel < 1 )
{
par = 0 ;
break ;
}
}
else if ( parlevel = = 1 & & ( tok2 - > str ( ) = = " , " ) )
{
+ + par ;
}
if ( parlevel = = 1 & & Token : : Match ( tok2 , std : : string ( " [(,] " + varnames + " [,)] " ) . c_str ( ) ) )
{
+ + par ;
break ;
}
}
if ( par = = 0 )
continue ;
// Find function..
2009-07-05 22:16:43 +02:00
const Token * ftok = _tokenizer - > getFunctionTokenByName ( tok - > str ( ) . c_str ( ) ) ;
2009-01-31 20:29:27 +01:00
if ( ! ftok )
continue ;
// Parse head of function..
ftok = ftok - > tokAt ( 2 ) ;
parlevel = 1 ;
while ( ftok & & parlevel = = 1 & & par > = 1 )
{
if ( ftok - > str ( ) = = " ( " )
+ + parlevel ;
else if ( ftok - > str ( ) = = " ) " )
- - parlevel ;
else if ( ftok - > str ( ) = = " , " )
- - par ;
else if ( par = = 1 & & parlevel = = 1 & & Token : : Match ( ftok , " %var% [,)] " ) )
{
// Parameter name..
const char * parname [ 2 ] ;
2009-05-03 20:10:59 +02:00
parname [ 0 ] = ftok - > str ( ) . c_str ( ) ;
2009-01-31 20:29:27 +01:00
parname [ 1 ] = 0 ;
// Goto function body..
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
ftok = ftok - > next ( ) ;
ftok = ftok ? ftok - > next ( ) : 0 ;
// Check variable usage in the function..
_callStack . push_back ( tok ) ;
2009-07-05 22:16:43 +02:00
checkScope ( ftok , parname , size , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
_callStack . pop_back ( ) ;
// break out..
break ;
}
ftok = ftok - > next ( ) ;
}
}
}
}
//---------------------------------------------------------------------------
// Checking local variables in a scope
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : checkGlobalAndLocalVariable ( )
2009-01-31 20:29:27 +01:00
{
int indentlevel = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
- - indentlevel ;
2009-02-11 17:12:29 +01:00
const char * varname [ 2 ] = { 0 } ;
unsigned int size = 0 ;
const char * type = 0 ;
unsigned int varid = 0 ;
int nextTok = 0 ;
2009-01-31 20:29:27 +01:00
2009-06-02 18:56:53 +02:00
// if the previous token exists, it must be either a variable name or "[;{}]"
if ( tok - > previous ( ) & & ( ! tok - > previous ( ) - > isName ( ) & & ! Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) )
continue ;
2009-06-01 19:21:08 +02:00
if ( Token : : Match ( tok , " %type% *| %var% [ %num% ] [;=] " ) )
2009-02-11 17:12:29 +01:00
{
2009-06-01 19:21:08 +02:00
unsigned int varpos = 1 ;
if ( tok - > next ( ) - > str ( ) = = " * " )
+ + varpos ;
varname [ 0 ] = tok - > strAt ( varpos ) ;
size = std : : strtoul ( tok - > strAt ( varpos + 2 ) , NULL , 10 ) ;
type = tok - > strAt ( varpos - 1 ) ;
varid = tok - > tokAt ( varpos ) - > varId ( ) ;
nextTok = varpos + 5 ;
2009-02-11 17:12:29 +01:00
}
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = new %type% [ %num% ] " ) )
{
varname [ 0 ] = tok - > strAt ( 1 ) ;
size = std : : strtoul ( tok - > strAt ( 6 ) , NULL , 10 ) ;
type = tok - > strAt ( 4 ) ;
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 8 ;
}
2009-03-16 18:11:09 +01:00
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = malloc ( %num% ) ; " ) )
{
varname [ 0 ] = tok - > strAt ( 1 ) ;
size = std : : strtoul ( tok - > strAt ( 5 ) , NULL , 10 ) ;
type = " char " ;
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 7 ;
}
2009-02-11 17:12:29 +01:00
else
{
continue ;
}
2009-01-31 20:29:27 +01:00
2009-07-05 22:16:43 +02:00
int total_size = size * ( ( * type = = ' * ' ) ? 4 : _tokenizer - > sizeOfType ( type ) ) ;
2009-02-11 17:12:29 +01:00
if ( total_size = = 0 )
continue ;
2009-01-31 20:29:27 +01:00
2009-02-11 17:12:29 +01:00
// The callstack is empty
_callStack . clear ( ) ;
2009-07-05 22:16:43 +02:00
checkScope ( tok - > tokAt ( nextTok ) , varname , size , total_size , varid ) ;
2009-01-31 20:29:27 +01:00
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Checking member variables of structs..
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : checkStructVariable ( )
2009-01-31 20:29:27 +01:00
{
const char declstruct [ ] = " struct|class %var% { " ;
for ( const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , declstruct ) ;
tok ; tok = Token : : findmatch ( tok - > next ( ) , declstruct ) )
{
const std : : string & structname = tok - > next ( ) - > str ( ) ;
// Found a struct declaration. Search for arrays..
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " } " )
break ;
int ivar = 0 ;
if ( Token : : Match ( tok2 - > next ( ) , " %type% %var% [ %num% ] ; " ) )
ivar = 2 ;
else if ( Token : : Match ( tok2 - > next ( ) , " %type% %type% %var% [ %num% ] ; " ))
ivar = 3 ;
else if ( Token : : Match ( tok2 - > next ( ) , " %type% * %var% [ %num% ] ; " ))
ivar = 3 ;
else if ( Token : : Match ( tok2 - > next ( ) , " %type% %type% * %var% [ %num% ] ; " ))
ivar = 4 ;
else
continue ;
const char * varname [ 3 ] = { 0 , 0 , 0 } ;
varname [ 1 ] = tok2 - > strAt ( ivar ) ;
int arrsize = std : : atoi ( tok2 - > strAt ( ivar + 2 ) ) ;
2009-07-05 22:16:43 +02:00
int total_size = arrsize * _tokenizer - > sizeOfType ( tok2 - > strAt ( 1 ) ) ;
2009-01-31 20:29:27 +01:00
if ( total_size = = 0 )
continue ;
// Class member variable => Check functions
if ( tok - > str ( ) = = " class " )
{
std : : string func_pattern ( structname + " :: %var% ( " ) ;
const Token * tok3 = Token : : findmatch ( _tokenizer - > tokens ( ) , func_pattern . c_str ( ) ) ;
while ( tok3 )
{
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
{
if ( Token : : Match ( tok4 , " [;{}] " ) )
break ;
if ( Token : : simpleMatch ( tok4 , " ) { " ) )
{
const char * names [ 2 ] = { varname [ 1 ] , 0 } ;
2009-07-05 22:16:43 +02:00
checkScope ( tok4 - > tokAt ( 2 ) , names , arrsize , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
break ;
}
}
tok3 = Token : : findmatch ( tok3 - > next ( ) , func_pattern . c_str ( ) ) ;
}
}
for ( const Token * tok3 = _tokenizer - > tokens ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) ! = structname )
continue ;
// Declare variable: Fred fred1;
if ( Token : : Match ( tok3 - > next ( ) , " %var% ; " ) )
varname [ 0 ] = tok3 - > strAt ( 1 ) ;
// Declare pointer: Fred *fred1
else if ( Token : : Match ( tok3 - > next ( ) , " * %var% [,) ; = ] " ))
varname [ 0 ] = tok3 - > strAt ( 2 ) ;
else
continue ;
// Goto end of statement.
const Token * CheckTok = NULL ;
while ( tok3 )
{
// End of statement.
if ( tok3 - > str ( ) = = " ; " )
{
CheckTok = tok3 ;
break ;
}
// End of function declaration..
if ( Token : : simpleMatch ( tok3 , " ) ; " ) )
break ;
// Function implementation..
if ( Token : : simpleMatch ( tok3 , " ) { " ) )
{
CheckTok = tok3 - > tokAt ( 2 ) ;
break ;
}
tok3 = tok3 - > next ( ) ;
}
if ( ! tok3 )
break ;
if ( ! CheckTok )
continue ;
// Check variable usage..
2009-07-05 22:16:43 +02:00
checkScope ( CheckTok , varname , arrsize , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
}
}
}
}
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : bufferOverrun ( )
2009-01-31 20:29:27 +01:00
{
2009-07-05 22:16:43 +02:00
checkGlobalAndLocalVariable ( ) ;
checkStructVariable ( ) ;
2009-01-31 20:29:27 +01:00
}
//---------------------------------------------------------------------------
2009-09-25 18:23:44 +02:00
int CheckBufferOverrun : : count ( const std : : string & input_string )
{
int flag = 1 ;
int input_string_size = 0 ;
int on_on_next = 0 ;
std : : string digits_string = " " ;
int digits = 0 ;
2009-09-26 16:19:18 +02:00
int check_for_i_d_x_f = 0 ;
2009-09-25 18:23:44 +02:00
for ( std : : string : : size_type i = 0 ; i ! = input_string . size ( ) ; i + + )
{
if ( on_on_next = = 1 )
{
flag = 1 ;
on_on_next = 0 ;
}
switch ( input_string [ i ] )
{
2009-09-26 16:19:18 +02:00
case ' f ' :
case ' x ' :
case ' X ' :
2009-09-25 18:23:44 +02:00
case ' d ' :
case ' i ' :
2009-09-26 16:19:18 +02:00
check_for_i_d_x_f = 1 ;
2009-09-25 18:23:44 +02:00
case ' c ' :
case ' e ' :
case ' E ' :
case ' g ' :
case ' o ' :
case ' s ' :
case ' u ' :
case ' p ' :
case ' n ' :
if ( flag = = 0 ) on_on_next = 1 ;
break ;
case ' % ' :
if ( flag = = 1 ) flag = 0 ;
break ;
case ' / ' :
input_string_size - - ;
break ;
}
if ( flag ) input_string_size + + ;
else
digits_string + = input_string [ i ] ;
if ( on_on_next = = 1 & & flag = = 0 )
{
2009-09-26 16:59:16 +02:00
//std::cout << digits_string;
2009-09-26 16:19:18 +02:00
2009-09-25 18:23:44 +02:00
digits_string = digits_string . substr ( 1 , digits_string . size ( ) ) ;
2009-09-26 16:19:18 +02:00
if ( check_for_i_d_x_f = = 1 ) digits + = std : : max ( abs ( atoi ( digits_string . c_str ( ) ) ) , 1 ) ;
else
digits + = abs ( atoi ( digits_string . c_str ( ) ) ) ;
2009-09-25 18:23:44 +02:00
2009-09-26 16:19:18 +02:00
digits_string = " " ;
check_for_i_d_x_f = 0 ;
2009-09-25 18:23:44 +02:00
}
}
return input_string_size + 1 + digits ;
}
2009-01-31 20:29:27 +01:00