2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2011-01-09 20:33:36 +01:00
* Copyright ( C ) 2007 - 2011 Daniel Marjamäki and Cppcheck team .
2009-01-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"
2011-06-23 04:44:11 +02:00
# include "symboldatabase.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>
2010-03-28 15:56:13 +02:00
# include <climits>
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
2010-11-21 11:48:27 +01:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const Token * tok , MathLib : : bigint size , MathLib : : bigint index )
2009-01-31 20:29:27 +01:00
{
2010-11-06 09:10:10 +01:00
if ( size > = 1 )
2010-05-19 19:23:09 +02:00
{
std : : ostringstream errmsg ;
errmsg < < " Array ' " ;
if ( tok )
errmsg < < tok - > str ( ) ;
else
errmsg < < " array " ;
errmsg < < " [ " < < size < < " ]' index " < < index < < " out of bounds " ;
reportError ( tok , Severity : : error , " arrayIndexOutOfBounds " , errmsg . str ( ) . c_str ( ) ) ;
}
2009-03-21 21:33:27 +01:00
}
2010-12-31 09:30:56 +01:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const Token * tok , const ArrayInfo & arrayInfo , const std : : vector < MathLib : : bigint > & index )
2010-04-18 11:08:29 +02:00
{
std : : ostringstream oss ;
2011-06-23 02:35:58 +02:00
oss < < " Array ' " < < arrayInfo . varname ( ) ;
for ( unsigned int i = 0 ; i < arrayInfo . num ( ) . size ( ) ; + + i )
oss < < " [ " < < arrayInfo . num ( i ) < < " ] " ;
2010-04-23 16:26:40 +02:00
oss < < " ' index " ;
if ( index . size ( ) = = 1 )
oss < < index [ 0 ] ;
else
{
2011-06-23 02:35:58 +02:00
oss < < arrayInfo . varname ( ) ;
2010-04-23 16:26:40 +02:00
for ( unsigned int i = 0 ; i < index . size ( ) ; + + i )
oss < < " [ " < < index [ i ] < < " ] " ;
}
oss < < " out of bounds " ;
2010-04-18 11:08:29 +02:00
reportError ( tok , Severity : : error , " arrayIndexOutOfBounds " , oss . str ( ) . c_str ( ) ) ;
}
2010-12-31 09:30:56 +01:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const std : : list < const Token * > & callstack , const ArrayInfo & arrayInfo , const std : : vector < MathLib : : bigint > & index )
2010-08-05 11:01:47 +02:00
{
std : : ostringstream oss ;
2011-06-23 02:35:58 +02:00
oss < < " Array ' " < < arrayInfo . varname ( ) ;
for ( unsigned int i = 0 ; i < arrayInfo . num ( ) . size ( ) ; + + i )
oss < < " [ " < < arrayInfo . num ( i ) < < " ] " ;
2010-08-05 11:01:47 +02:00
oss < < " ' index " ;
if ( index . size ( ) = = 1 )
oss < < index [ 0 ] ;
else
{
2011-06-23 02:35:58 +02:00
oss < < arrayInfo . varname ( ) ;
2010-08-05 11:01:47 +02:00
for ( unsigned int i = 0 ; i < index . size ( ) ; + + i )
oss < < " [ " < < index [ i ] < < " ] " ;
}
oss < < " out of bounds " ;
reportError ( callstack , Severity : : error , " arrayIndexOutOfBounds " , oss . str ( ) . c_str ( ) ) ;
}
2010-02-21 15:23:50 +01:00
void CheckBufferOverrun : : bufferOverrun ( const Token * tok , const std : : string & varnames )
2009-03-21 21:33:27 +01:00
{
2010-02-21 15:23:50 +01:00
std : : string v = varnames ;
2010-04-02 07:30:58 +02:00
while ( v . find ( " " ) ! = std : : string : : npos )
2010-02-21 15:23:50 +01:00
v . erase ( v . find ( " " ) , 1 ) ;
std : : string errmsg ( " Buffer access out-of-bounds " ) ;
2010-04-02 07:30:58 +02:00
if ( ! v . empty ( ) )
2010-02-21 15:23:50 +01:00
errmsg + = " : " + v ;
2010-05-16 15:30:39 +02:00
reportError ( tok , Severity : : error , " bufferAccessOutOfBounds " , errmsg ) ;
2009-03-21 21:33:27 +01:00
}
2011-08-21 21:18:41 +02:00
void CheckBufferOverrun : : possibleBufferOverrunError ( const Token * tok , const std : : string & src , const std : : string & dst , bool cat )
2011-08-21 20:44:55 +02:00
{
2011-08-21 21:18:41 +02:00
if ( cat )
reportError ( tok , Severity : : warning , " possibleBufferAccessOutOfBounds " ,
" Possible buffer overflow if strlen( " + src + " ) is larger than sizeof( " + dst + " )-strlen( " + dst + " ). \n "
" The source buffer is larger than the destination buffer so there is the potential for overflowing the destination buffer. " ) ;
else
reportError ( tok , Severity : : warning , " possibleBufferAccessOutOfBounds " ,
" Possible buffer overflow if strlen( " + src + " ) is larger than or equal to sizeof( " + dst + " ). \n "
" The source buffer is larger than the destination buffer so there is the potential for overflowing the destination buffer. " ) ;
2011-08-21 20:44:55 +02:00
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : strncatUsage ( const Token * tok )
2009-03-21 21:33:27 +01:00
{
2011-08-07 09:28:08 +02:00
if ( _settings & & ! _settings - > isEnabled ( " style " ) )
2009-10-13 22:33:41 +02:00
return ;
2011-01-03 17:33:03 +01:00
reportError ( tok , Severity : : warning , " strncatUsage " ,
" Dangerous usage of strncat - 3rd parameter is the maximum number of characters to append. \n "
" strncat appends at max its 3rd parameter's amount of characters. The safe way to use "
" strncat is to calculate remaining space in the buffer and use it as 3rd parameter. " ) ;
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
}
2011-01-01 20:56:21 +01:00
void CheckBufferOverrun : : pointerOutOfBounds ( const Token * tok , const std : : string & object )
2010-12-26 21:23:28 +01:00
{
2011-01-01 20:56:21 +01:00
reportError ( tok , Severity : : portability , " pointerOutOfBounds " , " Undefined behaviour: pointer arithmetic result does not point into or just past the end of the " + object + " \n "
2010-12-26 21:23:28 +01:00
" Undefined behaviour: Using pointer arithmetic so that the result does not point into or just past the end of the same object. Further information: https://www.securecoding.cert.org/confluence/display/seccode/ARR30-C.+Do+not+form+or+use+out+of+bounds+pointers+or+array+subscripts " ) ;
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : sizeArgumentAsChar ( const Token * tok )
2009-03-25 07:25:10 +01:00
{
2011-08-07 09:28:08 +02:00
if ( _settings & & ! _settings - > isEnabled ( " style " ) )
2009-10-13 22:33:41 +02:00
return ;
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " sizeArgumentAsChar " , " The size argument is given as a char constant " ) ;
2009-03-25 07:25:10 +01:00
}
2009-12-18 17:26:15 +01:00
void CheckBufferOverrun : : terminateStrncpyError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " terminateStrncpy " , " After a strncpy() the buffer should be zero-terminated " ) ;
2009-12-18 17:26:15 +01:00
}
2010-06-02 07:41:07 +02:00
void CheckBufferOverrun : : cmdLineArgsError ( const Token * tok )
{
reportError ( tok , Severity : : error , " insecureCmdLineArgs " , " Buffer overrun possible for long cmd-line args " ) ;
}
2009-12-18 17:26:15 +01:00
2009-01-31 20:29:27 +01:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check array usage..
//---------------------------------------------------------------------------
2010-02-27 22:47:56 +01:00
/**
* @ brief This is a helper class to be used with std : : find_if
*/
class TokenStrEquals
{
public :
/**
* @ param str Token : : str ( ) is compared against this .
*/
TokenStrEquals ( const std : : string & str )
2010-04-15 20:08:51 +02:00
: value ( str )
2010-02-27 22:47:56 +01:00
{
}
/**
* Called automatically by std : : find_if
* @ param tok Token inside the list
*/
bool operator ( ) ( const Token * tok ) const
{
return value = = tok - > str ( ) ;
}
private :
2010-04-13 19:25:08 +02:00
TokenStrEquals & operator = ( const TokenStrEquals & ) ; // disallow assignments
2010-02-27 22:47:56 +01:00
const std : : string value ;
} ;
2010-12-31 17:43:38 +01:00
/**
* bailout if variable is used inside if / else / switch block or if there is " break "
* @ param tok token for " if " or " switch "
* @ param varid variable id
* @ return is bailout recommended ?
*/
static bool bailoutIfSwitch ( const Token * tok , const unsigned int varid )
{
2011-01-06 13:02:21 +01:00
// Used later to check if the body belongs to a "if"
2010-12-31 17:43:38 +01:00
const std : : string str1 ( tok - > str ( ) ) ;
2011-01-06 13:02:21 +01:00
// Count { and }
2010-12-31 17:43:38 +01:00
unsigned int indentlevel = 0 ;
for ( ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
indentlevel + + ;
else if ( tok - > str ( ) = = " } " )
{
// scan the else-block
if ( indentlevel = = 1 & & Token : : simpleMatch ( tok , " } else { " ) )
{
- - indentlevel ;
continue ;
}
else if ( indentlevel < = 1 )
{
break ;
}
- - indentlevel ;
}
// If scanning a "if" block then bailout for "break"
else if ( str1 = = " if " & & tok - > str ( ) = = " break " )
return true ;
2010-12-31 18:07:46 +01:00
// bailout for "return"
else if ( tok - > str ( ) = = " return " )
return true ;
2010-12-31 17:43:38 +01:00
// bailout if varid is found
else if ( tok - > varId ( ) = = varid )
return true ;
}
// No bailout stuff found => return false
return false ;
}
2010-04-21 18:33:21 +02:00
/**
* Parse for loop initialization statement . Look for a counter variable
2010-05-08 10:39:45 +02:00
* \ param tok [ in ] first token inside the parentheses
2010-04-21 18:33:21 +02:00
* \ param varid [ out ] varid of counter variable
* \ param init_value [ out ] init value of counter variable
* \ return success = > pointer to the for loop condition . fail = > 0
*/
static const Token * for_init ( const Token * tok , unsigned int & varid , std : : string & init_value )
{
if ( Token : : Match ( tok , " %var% = %any% ; " ) )
{
if ( tok - > tokAt ( 2 ) - > isNumber ( ) )
{
init_value = tok - > strAt ( 2 ) ;
}
varid = tok - > varId ( ) ;
tok = tok - > tokAt ( 4 ) ;
}
else if ( Token : : Match ( tok , " %type% %var% = %any% ; " ) )
{
if ( tok - > tokAt ( 3 ) - > isNumber ( ) )
{
init_value = tok - > strAt ( 3 ) ;
}
varid = tok - > next ( ) - > varId ( ) ;
tok = tok - > tokAt ( 5 ) ;
}
else if ( Token : : Match ( tok , " %type% %type% %var% = %any% ; " ) )
{
if ( tok - > tokAt ( 4 ) - > isNumber ( ) )
{
init_value = tok - > strAt ( 4 ) ;
}
varid = tok - > tokAt ( 2 ) - > varId ( ) ;
tok = tok - > tokAt ( 6 ) ;
}
else
return 0 ;
return tok ;
}
/** Parse for condition */
static bool for_condition ( const Token * const tok2 , unsigned int varid , std : : string & min_value , std : : string & max_value , std : : string & strindex , bool & maxMinFlipped )
{
2011-01-09 18:51:28 +01:00
if ( Token : : Match ( tok2 , " %varid% < %num% ; " , varid ) | |
Token : : Match ( tok2 , " %varid% != %num% ; ++ %varid% " , varid ) | |
Token : : Match ( tok2 , " %varid% != %num% ; %varid% ++ " , varid ) )
2010-04-21 18:33:21 +02:00
{
maxMinFlipped = false ;
2010-11-20 11:48:03 +01:00
const MathLib : : bigint value = MathLib : : toLongNumber ( tok2 - > strAt ( 2 ) ) ;
max_value = MathLib : : toString < MathLib : : bigint > ( value - 1 ) ;
2010-04-21 18:33:21 +02:00
}
else if ( Token : : Match ( tok2 , " %varid% <= %num% ; " , varid ) )
{
maxMinFlipped = false ;
max_value = tok2 - > strAt ( 2 ) ;
}
2011-02-02 16:41:43 +01:00
else if ( Token : : Match ( tok2 , " %num% < %varid% ; " , varid ) | |
2011-01-09 18:51:28 +01:00
Token : : Match ( tok2 , " %num% != %varid% ; ++ %varid% " , varid ) | |
Token : : Match ( tok2 , " %num% != %varid% ; %varid% ++ " , varid ) )
2010-04-21 18:33:21 +02:00
{
maxMinFlipped = true ;
2010-11-20 11:48:03 +01:00
const MathLib : : bigint value = MathLib : : toLongNumber ( tok2 - > str ( ) ) ;
2010-04-21 18:33:21 +02:00
max_value = min_value ;
2010-11-20 11:48:03 +01:00
min_value = MathLib : : toString < MathLib : : bigint > ( value + 1 ) ;
2010-04-21 18:33:21 +02:00
}
else if ( Token : : Match ( tok2 , " %num% <= %varid% ; " , varid ) )
{
maxMinFlipped = true ;
max_value = min_value ;
min_value = tok2 - > str ( ) ;
}
else
{
return false ;
}
strindex = tok2 - > isName ( ) ? tok2 - > str ( ) : tok2 - > strAt ( 2 ) ;
return true ;
}
2011-04-04 17:33:43 +02:00
/**
* calculate maximum value of loop variable
* @ param stepvalue token that contains the step value
* @ param min_value the minimum value of loop variable
* @ param max_value maximum value of the loop variable
*/
static bool for_maxvalue ( const Token * const stepvalue , const std : : string & min_value , std : : string & max_value )
{
if ( ! MathLib : : isInt ( stepvalue - > str ( ) ) )
return false ;
// We have for example code: "for(i=2;i<22;i+=6)
// We can calculate that max value for i is 20, not 21
// 21-2 = 19
// 19/6 = 3
// 6*3+2 = 20
const MathLib : : bigint num = MathLib : : toLongNumber ( stepvalue - > str ( ) ) ;
MathLib : : bigint max = MathLib : : toLongNumber ( max_value ) ;
const MathLib : : bigint min = MathLib : : toLongNumber ( min_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_value = MathLib : : toString < MathLib : : bigint > ( max ) ;
return true ;
}
2010-04-21 18:33:21 +02:00
/**
2010-05-08 10:39:45 +02:00
* Parse the third sub - statement in for head
2010-04-21 18:33:21 +02:00
* \ param tok first token
* \ param varid variable id of counter
* \ param min_value min value of counter
* \ param max_value max value of counter
* \ param maxMinFlipped counting from max to min
*/
static bool for3 ( const Token * const tok ,
unsigned int varid ,
std : : string & min_value ,
std : : string & max_value ,
const bool maxMinFlipped )
{
assert ( tok ! = 0 ) ;
if ( Token : : Match ( tok , " %varid% += %num% ) " , varid ) | |
Token : : Match ( tok , " %varid% = %num% + %varid% ) " , varid ) )
{
2011-04-04 17:33:43 +02:00
if ( ! for_maxvalue ( tok - > tokAt ( 2 ) , min_value , max_value ) )
2010-04-21 18:33:21 +02:00
return false ;
}
else if ( Token : : Match ( tok , " %varid% = %varid% + %num% ) " , varid ) )
{
2011-04-04 17:33:43 +02:00
if ( ! for_maxvalue ( tok - > tokAt ( 4 ) , min_value , max_value ) )
2010-04-21 18:33:21 +02:00
return false ;
}
else if ( Token : : Match ( tok , " %varid% -= %num% ) " , varid ) | |
Token : : Match ( tok , " %varid% = %num% - %varid% ) " , varid ) )
{
2011-04-04 17:33:43 +02:00
if ( ! for_maxvalue ( tok - > tokAt ( 2 ) , min_value , max_value ) )
2010-04-21 18:33:21 +02:00
return false ;
}
else if ( Token : : Match ( tok , " %varid% = %varid% - %num% ) " , varid ) )
{
2011-04-04 17:33:43 +02:00
if ( ! for_maxvalue ( tok - > tokAt ( 4 ) , min_value , max_value ) )
2010-04-21 18:33:21 +02:00
return false ;
}
else if ( Token : : Match ( tok , " --| %varid% --| ) " , varid ) )
{
if ( ! maxMinFlipped & & MathLib : : toLongNumber ( min_value ) < MathLib : : toLongNumber ( max_value ) )
{
// Code relies on the fact that integer will overflow:
// for (unsigned int i = 3; i < 5; --i)
// Set min value in this case to zero.
max_value = min_value ;
min_value = " 0 " ;
}
}
else if ( ! Token : : Match ( tok , " ++| %varid% ++| ) " , varid ) )
{
return false ;
}
return true ;
}
/**
* Check is the counter variable increased elsewhere inside the loop or used
* for anything else except reading
2010-06-14 07:54:41 +02:00
* \ param tok1 first token of for - body
2010-04-21 18:33:21 +02:00
* \ param varid counter variable id
* \ return bailout needed = > true
*/
static bool for_bailout ( const Token * const tok1 , unsigned int varid )
{
for ( const Token * loopTok = tok1 ; loopTok & & loopTok ! = tok1 - > link ( ) ; loopTok = loopTok - > next ( ) )
{
if ( loopTok - > varId ( ) = = varid )
{
// Counter variable used inside loop
if ( Token : : Match ( loopTok - > next ( ) , " +=|-=|++|--|= " ) | |
Token : : Match ( loopTok - > previous ( ) , " ++|-- " ) )
{
return true ;
}
}
}
return false ;
}
void CheckBufferOverrun : : parse_for_body ( const Token * tok2 , const ArrayInfo & arrayInfo , const std : : string & strindex , bool condition_out_of_bounds , unsigned int counter_varid , const std : : string & min_counter_value , const std : : string & max_counter_value )
{
2011-06-23 02:35:58 +02:00
const std : : string pattern ( ( arrayInfo . varid ( ) ? std : : string ( " %varid% " ) : arrayInfo . varname ( ) ) + " [ " + strindex + " ] " ) ;
2010-04-21 18:33:21 +02:00
2011-01-06 13:02:21 +01:00
// count { and } for tok2
2010-04-21 18:33:21 +02:00
int indentlevel2 = 0 ;
for ( ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ; " & & indentlevel2 = = 0 )
break ;
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
if ( tok2 - > str ( ) = = " } " )
{
- - indentlevel2 ;
if ( indentlevel2 < = 0 )
break ;
}
2011-02-12 11:31:10 +01:00
// TODO: try to reduce false negatives. This is just a quick fix
// for TestBufferOverrun::array_index_for_question
if ( tok2 - > str ( ) = = " ? " )
break ;
2011-03-08 19:49:56 +01:00
if ( Token : : simpleMatch ( tok2 , " for ( " ) & & Token : : simpleMatch ( tok2 - > next ( ) - > link ( ) , " ) { " ) )
{
const Token * endpar = tok2 - > next ( ) - > link ( ) ;
const Token * startbody = endpar - > next ( ) ;
const Token * endbody = startbody - > link ( ) ;
tok2 = endbody ;
continue ;
}
2010-04-21 18:33:21 +02:00
if ( Token : : Match ( tok2 , " if|switch " ) )
{
2011-06-23 02:35:58 +02:00
if ( bailoutIfSwitch ( tok2 , arrayInfo . varid ( ) ) )
2010-12-28 20:46:31 +01:00
break ;
2010-04-21 18:33:21 +02:00
}
2011-06-23 02:35:58 +02:00
if ( condition_out_of_bounds & & Token : : Match ( tok2 , pattern . c_str ( ) , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
2011-06-23 02:35:58 +02:00
bufferOverrun ( tok2 , arrayInfo . varname ( ) ) ;
2010-04-21 18:33:21 +02:00
break ;
}
2011-06-23 02:35:58 +02:00
else if ( arrayInfo . varid ( ) & & counter_varid > 0 & & ! min_counter_value . empty ( ) & & ! max_counter_value . empty ( ) )
2010-04-21 18:33:21 +02:00
{
2011-01-02 14:16:58 +01:00
// Is the loop variable used to calculate the array index?
// In this scope it is determined if such calculated
// array indexes are out of bounds.
// Only the minimum and maximum results of the calculation is
// determined
// Minimum calculated array index
2010-04-21 18:33:21 +02:00
int min_index = 0 ;
2011-01-02 14:16:58 +01:00
// Maximum calculated array index
2010-04-21 18:33:21 +02:00
int max_index = 0 ;
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok2 , " %varid% [ %var% +|-|*|/ %num% ] " , arrayInfo . varid ( ) ) & &
2010-04-21 18:33:21 +02:00
tok2 - > tokAt ( 2 ) - > varId ( ) = = counter_varid )
{
2011-01-02 14:16:58 +01:00
// operator: +-*/
2010-04-21 18:33:21 +02:00
const char action = tok2 - > strAt ( 3 ) [ 0 ] ;
2011-01-02 14:16:58 +01:00
// second operator
2010-04-21 18:33:21 +02:00
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());
2010-07-24 10:25:03 +02:00
min_index = std : : atoi ( MathLib : : calculate ( min_counter_value , second , action , _tokenizer ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( max_counter_value , second , action , _tokenizer ) . c_str ( ) ) ;
2010-04-21 18:33:21 +02:00
}
2011-06-23 02:35:58 +02:00
else if ( Token : : Match ( tok2 , " %varid% [ %num% +|-|*|/ %var% ] " , arrayInfo . varid ( ) ) & &
2010-04-21 18:33:21 +02:00
tok2 - > tokAt ( 4 ) - > varId ( ) = = counter_varid )
{
2011-01-02 14:16:58 +01:00
// operator: +-*/
2010-04-21 18:33:21 +02:00
const char action = tok2 - > strAt ( 3 ) [ 0 ] ;
2011-01-02 14:16:58 +01:00
// first operand
2010-04-21 18:33:21 +02:00
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());
2010-07-24 10:25:03 +02:00
min_index = std : : atoi ( MathLib : : calculate ( first , min_counter_value , action , _tokenizer ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( first , max_counter_value , action , _tokenizer ) . c_str ( ) ) ;
2010-04-21 18:33:21 +02:00
}
//printf("min_index = %d, max_index = %d, size = %d\n", min_index, max_index, size);
2010-04-25 07:34:50 +02:00
if ( min_index < 0 | | max_index < 0 )
{
2011-06-23 02:35:58 +02:00
arrayIndexOutOfBounds ( tok2 , ( int ) arrayInfo . num ( 0 ) , std : : min ( min_index , max_index ) ) ;
2010-04-25 07:34:50 +02:00
}
2011-06-23 02:35:58 +02:00
if ( min_index > = ( int ) arrayInfo . num ( 0 ) | | max_index > = ( int ) arrayInfo . num ( 0 ) )
2010-04-21 18:33:21 +02:00
{
2011-06-23 02:35:58 +02:00
arrayIndexOutOfBounds ( tok2 , ( int ) arrayInfo . num ( 0 ) , std : : max ( min_index , max_index ) ) ;
2010-04-21 18:33:21 +02:00
}
}
}
}
2011-01-22 21:31:26 +01:00
void CheckBufferOverrun : : checkFunctionParameter ( const Token & tok , unsigned int par , const ArrayInfo & arrayInfo )
2010-04-21 19:27:28 +02:00
{
2011-01-02 14:16:58 +01:00
// total_size : which parameter in function call takes the total size?
2010-04-21 19:27:28 +02:00
std : : map < std : : string , unsigned int > total_size ;
2011-01-02 14:16:58 +01:00
2010-04-21 19:27:28 +02:00
total_size [ " fgets " ] = 2 ; // The second argument for fgets can't exceed the total size of the array
total_size [ " memcmp " ] = 3 ;
total_size [ " memcpy " ] = 3 ;
total_size [ " memmove " ] = 3 ;
2010-04-21 20:02:58 +02:00
if ( par = = 1 )
{
// reading from array
// if it is zero terminated properly there won't be buffer overruns
total_size [ " strncat " ] = 3 ;
total_size [ " strncpy " ] = 3 ;
total_size [ " memset " ] = 3 ;
2010-04-22 19:49:02 +02:00
total_size [ " fread " ] = 1001 ; // parameter 2 * parameter 3
total_size [ " fwrite " ] = 1001 ; // parameter 2 * parameter 3
2010-04-21 20:02:58 +02:00
}
2010-04-21 21:08:47 +02:00
2010-04-21 20:06:59 +02:00
if ( par = = 2 )
{
total_size [ " read " ] = 3 ;
2010-08-14 20:19:23 +02:00
total_size [ " pread " ] = 3 ;
2010-04-21 21:08:47 +02:00
total_size [ " write " ] = 3 ;
2010-08-14 20:19:23 +02:00
total_size [ " recv " ] = 3 ;
total_size [ " recvfrom " ] = 3 ;
total_size [ " send " ] = 3 ;
total_size [ " sendto " ] = 3 ;
2010-04-21 21:08:47 +02:00
}
2010-04-21 20:02:58 +02:00
std : : map < std : : string , unsigned int > : : const_iterator it = total_size . find ( tok . str ( ) ) ;
2010-04-21 19:27:28 +02:00
if ( it ! = total_size . end ( ) )
{
2011-06-23 02:35:58 +02:00
if ( arrayInfo . element_size ( ) = = 0 )
2010-10-24 11:32:27 +02:00
return ;
2011-01-06 13:02:21 +01:00
// arg : the index of the "wanted" argument in the function call.
2010-04-21 19:27:28 +02:00
unsigned int arg = it - > second ;
2011-01-06 13:02:21 +01:00
// Parse function call. When a ',' is seen, arg is decremented.
// if arg becomes 1 then the current function parameter is the wanted parameter.
// if arg becomes 1000 then multiply current and next argument.
2010-04-21 20:02:58 +02:00
for ( const Token * tok2 = tok . tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2010-04-21 19:27:28 +02:00
{
if ( tok2 - > str ( ) = = " ( " )
{
tok2 = tok2 - > link ( ) ;
continue ;
}
if ( tok2 - > str ( ) = = " ) " )
break ;
if ( tok2 - > str ( ) = = " , " )
{
- - arg ;
if ( arg = = 1 )
{
if ( Token : : Match ( tok2 , " , %num% ,|) " ) )
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint sz = MathLib : : toLongNumber ( tok2 - > strAt ( 1 ) ) ;
2010-12-31 09:30:56 +01:00
MathLib : : bigint elements = 1 ;
2011-06-23 02:35:58 +02:00
for ( unsigned int i = 0 ; i < arrayInfo . num ( ) . size ( ) ; + + i )
elements * = arrayInfo . num ( i ) ;
if ( sz < 0 | | sz > int ( elements * arrayInfo . element_size ( ) ) )
2010-04-21 19:27:28 +02:00
{
2011-06-23 02:35:58 +02:00
bufferOverrun ( & tok , arrayInfo . varname ( ) ) ;
2010-04-21 19:27:28 +02:00
}
}
2010-04-22 19:55:07 +02:00
else if ( Token : : Match ( tok2 , " , %any% ,|) " ) & & tok2 - > next ( ) - > str ( ) [ 0 ] = = ' \' ' )
{
sizeArgumentAsChar ( tok2 - > next ( ) ) ;
}
2010-04-21 19:27:28 +02:00
break ;
}
2010-04-22 19:49:02 +02:00
if ( arg = = 1000 ) // special code. This parameter multiplied with the next must not exceed total_size
{
if ( Token : : Match ( tok2 , " , %num% , %num% ,|) " ) )
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint sz = MathLib : : toLongNumber ( MathLib : : multiply ( tok2 - > strAt ( 1 ) , tok2 - > strAt ( 3 ) ) ) ;
2010-12-31 09:30:56 +01:00
MathLib : : bigint elements = 1 ;
2011-06-23 02:35:58 +02:00
for ( unsigned int i = 0 ; i < arrayInfo . num ( ) . size ( ) ; + + i )
elements * = arrayInfo . num ( i ) ;
if ( sz < 0 | | sz > int ( elements * arrayInfo . element_size ( ) ) )
2010-04-22 19:49:02 +02:00
{
2011-06-23 02:35:58 +02:00
bufferOverrun ( & tok , arrayInfo . varname ( ) ) ;
2010-04-22 19:49:02 +02:00
}
}
break ;
}
2010-04-21 19:27:28 +02:00
}
}
}
2010-08-05 11:01:47 +02:00
// Calling a user function?
// only 1-dimensional arrays can be checked currently
2011-06-23 02:35:58 +02:00
else if ( arrayInfo . num ( ) . size ( ) = = 1 )
2010-08-05 11:01:47 +02:00
{
const Token * ftok = _tokenizer - > getFunctionTokenByName ( tok . str ( ) . c_str ( ) ) ;
if ( Token : : Match ( ftok , " %var% ( " ) & & Token : : Match ( ftok - > next ( ) - > link ( ) , " ) const| { " ) )
{
// Get varid for the corresponding parameter..
unsigned int parameter = 1 ;
unsigned int parameterVarId = 0 ;
for ( const Token * ftok2 = ftok - > tokAt ( 2 ) ; ftok2 ; ftok2 = ftok2 - > next ( ) )
{
if ( ftok2 - > str ( ) = = " , " )
{
if ( parameter > = par )
break ;
+ + parameter ;
}
else if ( ftok2 - > str ( ) = = " ) " )
break ;
2011-06-29 18:44:05 +02:00
else if ( parameter = = par & & Token : : Match ( ftok2 , " %var% ,|)|[ " ) )
{
// check type..
const Token * type = ftok2 - > previous ( ) ;
while ( Token : : Match ( type , " *|const " ) )
type = type - > previous ( ) ;
if ( type & & _tokenizer - > sizeOfType ( type ) = = arrayInfo . element_size ( ) )
parameterVarId = ftok2 - > varId ( ) ;
}
2010-08-05 11:01:47 +02:00
}
// No parameterVarId => bail out
if ( parameterVarId = = 0 )
return ;
// Step into the function scope..
ftok = ftok - > next ( ) - > link ( ) ;
if ( ! Token : : Match ( ftok , " ) const| { " ) )
return ;
ftok = Token : : findmatch ( ftok , " { " ) ;
ftok = ftok - > next ( ) ;
// Check the parameter usage in the function scope..
for ( ; ftok ; ftok = ftok - > next ( ) )
{
2010-12-31 18:07:46 +01:00
if ( Token : : Match ( ftok , " if|for|while ( " ) )
{
// bailout if there is buffer usage..
if ( bailoutIfSwitch ( ftok , parameterVarId ) )
{
break ;
}
// no bailout is needed. skip the if-block
else
{
// goto end of if block..
ftok = ftok - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
if ( Token : : simpleMatch ( ftok , " } else { " ) )
ftok = ftok - > tokAt ( 2 ) - > link ( ) ;
continue ;
}
}
2010-08-05 11:01:47 +02:00
if ( ftok - > str ( ) = = " } " )
break ;
if ( ftok - > varId ( ) = = parameterVarId )
{
2010-10-14 20:00:32 +02:00
if ( Token : : Match ( ftok - > previous ( ) , " -- %var% " ) | |
Token : : Match ( ftok , " %var% -- " ) )
break ;
2011-04-09 18:37:03 +02:00
if ( Token : : Match ( ftok - > previous ( ) , " =|;|{|}|%op% %var% [ %num% ] " ) )
2010-08-05 11:01:47 +02:00
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( ftok - > strAt ( 2 ) ) ;
2011-06-23 02:35:58 +02:00
if ( index > = 0 & & arrayInfo . num ( 0 ) > 0 & & index > = arrayInfo . num ( 0 ) )
2010-08-05 11:01:47 +02:00
{
std : : list < const Token * > callstack ;
callstack . push_back ( & tok ) ;
callstack . push_back ( ftok ) ;
2010-12-31 09:30:56 +01:00
std : : vector < MathLib : : bigint > indexes ;
indexes . push_back ( index ) ;
2010-08-05 11:01:47 +02:00
2010-08-06 21:02:43 +02:00
arrayIndexOutOfBounds ( callstack , arrayInfo , indexes ) ;
2010-08-05 11:01:47 +02:00
}
}
}
}
}
}
2010-04-21 19:27:28 +02:00
}
2011-01-22 21:31:26 +01:00
void CheckBufferOverrun : : checkFunctionCall ( const Token * tok , const ArrayInfo & arrayInfo )
{
// 1st parameter..
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " %varid% ,|) " , arrayInfo . varid ( ) ) )
2011-01-22 21:31:26 +01:00
checkFunctionParameter ( * tok , 1 , arrayInfo ) ;
2011-06-23 02:35:58 +02:00
else if ( Token : : Match ( tok - > tokAt ( 2 ) , " %varid% + %num% ,|) " , arrayInfo . varid ( ) ) )
2011-01-22 21:31:26 +01:00
{
const ArrayInfo ai ( arrayInfo . limit ( MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ) ) ;
checkFunctionParameter ( * tok , 1 , ai ) ;
}
// goto 2nd parameter and check it..
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
{
tok2 = tok2 - > link ( ) ;
continue ;
}
if ( tok2 - > str ( ) = = " ; " | | tok2 - > str ( ) = = " ) " )
break ;
if ( tok2 - > str ( ) = = " , " )
{
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok2 , " , %varid% ,|) " , arrayInfo . varid ( ) ) )
2011-01-22 21:31:26 +01:00
checkFunctionParameter ( * tok , 2 , arrayInfo ) ;
2011-06-23 02:35:58 +02:00
else if ( Token : : Match ( tok2 , " , %varid% + %num% ,|) " , arrayInfo . varid ( ) ) )
2011-01-22 21:31:26 +01:00
{
const ArrayInfo ai ( arrayInfo . limit ( MathLib : : toLongNumber ( tok2 - > strAt ( 3 ) ) ) ) ;
checkFunctionParameter ( * tok , 2 , ai ) ;
}
break ;
}
}
}
2010-04-21 18:33:21 +02:00
2011-02-10 21:56:06 +01:00
void CheckBufferOverrun : : checkScopeForBody ( const Token * tok , const ArrayInfo & arrayInfo , bool & bailout )
{
bailout = false ;
const Token * tok2 = tok - > tokAt ( 2 ) ;
2011-06-23 02:35:58 +02:00
const MathLib : : bigint size = arrayInfo . num ( 0 ) ;
2011-02-10 21:56:06 +01:00
// Check if there is a break in the body..
{
const Token * bodyStart = tok - > next ( ) - > link ( ) - > next ( ) ;
const Token * bodyEnd = bodyStart - > link ( ) ;
if ( Token : : findmatch ( bodyStart , " break ; " , bodyEnd ) )
return ;
}
unsigned int counter_varid = 0 ;
std : : string min_counter_value ;
std : : string max_counter_value ;
tok2 = for_init ( tok2 , counter_varid , min_counter_value ) ;
if ( tok2 = = 0 | | counter_varid = = 0 )
return ;
bool maxMinFlipped = false ;
std : : string strindex ;
if ( ! for_condition ( tok2 , counter_varid , min_counter_value , max_counter_value , strindex , maxMinFlipped ) )
return ;
// Get index variable and stopsize.
2011-02-12 18:34:12 +01:00
bool condition_out_of_bounds = bool ( size > 0 ) ;
2011-02-10 21:56:06 +01:00
if ( MathLib : : toLongNumber ( max_counter_value ) < size )
condition_out_of_bounds = false ;
if ( ! for3 ( tok2 - > tokAt ( 4 ) , counter_varid , min_counter_value , max_counter_value , maxMinFlipped ) )
return ;
if ( Token : : Match ( tok2 - > tokAt ( 4 ) , " %var% =|+=|-= " ) & & MathLib : : toLongNumber ( max_counter_value ) < = size )
condition_out_of_bounds = false ;
// Goto the end parenthesis of the for-statement: "for (x; y; z)" ..
tok2 = tok - > next ( ) - > link ( ) ;
if ( ! tok2 | | ! tok2 - > tokAt ( 5 ) )
{
bailout = true ;
return ;
}
// Check is the counter variable increased elsewhere inside the loop or used
// for anything else except reading
if ( for_bailout ( tok2 - > next ( ) , counter_varid ) )
{
bailout = true ;
return ;
}
parse_for_body ( tok2 - > next ( ) , arrayInfo , strindex , condition_out_of_bounds , counter_varid , min_counter_value , max_counter_value ) ;
}
2010-11-21 11:48:27 +01:00
void CheckBufferOverrun : : checkScope ( const Token * tok , const std : : vector < std : : string > & varname , const MathLib : : bigint size , const MathLib : : bigint total_size , unsigned int varid )
2009-01-31 20:29:27 +01:00
{
std : : string varnames ;
2010-04-02 07:30:58 +02:00
for ( unsigned int i = 0 ; i < varname . size ( ) ; + + i )
2010-02-14 20:46:40 +01:00
varnames + = ( i = = 0 ? " " : " . " ) + varname [ i ] ;
2009-01-31 20:29:27 +01:00
2010-08-12 19:39:19 +02:00
const unsigned char varc ( static_cast < unsigned char > ( varname . empty ( ) ? 0U : ( varname . size ( ) - 1 ) * 2U ) ) ;
2010-03-09 12:41:40 +01:00
2011-02-02 16:48:00 +01:00
if ( Token : : simpleMatch ( tok , " return " ) )
2010-02-05 22:55:10 +01:00
{
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2010-02-05 22:55:10 +01:00
return ;
}
2009-01-31 20:29:27 +01:00
// Array index..
2010-04-02 07:30:58 +02:00
if ( varid > 0 )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %varid% [ %num% ] " , varid ) )
2009-01-31 20:29:27 +01:00
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) ;
2010-04-18 20:51:39 +02:00
if ( index > = size )
2009-01-31 20:29:27 +01:00
{
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( tok , size , index ) ;
2009-01-31 20:29:27 +01:00
}
}
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , ( varnames + " [ %num% ] " ) . c_str ( ) ) )
2009-01-31 20:29:27 +01:00
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 2 + varc ) ) ;
2010-04-18 20:51:39 +02:00
if ( index > = size )
2009-01-31 20:29:27 +01:00
{
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( tok - > tokAt ( varc ) , size , index ) ;
2009-01-31 20:29:27 +01:00
}
}
2011-01-01 20:56:21 +01:00
// If the result of pointer arithmetic means that the pointer is
// out of bounds then this flag will be set.
bool pointerIsOutOfBounds = false ;
2011-01-06 13:02:21 +01:00
// Count { and } for tok
2009-01-31 20:29:27 +01:00
int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-31 20:29:27 +01:00
{
+ + indentlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-31 20:29:27 +01:00
{
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < 0 )
2009-01-31 20:29:27 +01:00
return ;
}
2010-04-02 07:30:58 +02:00
if ( varid ! = 0 & & Token : : Match ( tok , " %varid% = new|malloc|realloc " , varid ) )
2010-02-10 22:11:08 +01:00
{
// Abort
break ;
}
2011-08-08 18:22:15 +02:00
// reassign buffer => bailout
if ( varid > 0 & &
Token : : Match ( tok , " [;{}] %varid% = " , varid ) & &
! Token : : Match ( tok - > tokAt ( 3 ) , " %varid% " , varid ) )
break ;
2009-01-31 20:29:27 +01:00
// Array index..
2010-04-02 07:30:58 +02:00
if ( varid > 0 )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! tok - > isName ( ) & & ! Token : : Match ( tok , " [.&] " ) & & Token : : Match ( tok - > next ( ) , " %varid% [ %num% ] " , varid ) )
2009-01-31 20:29:27 +01:00
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 3 ) ) ;
2010-04-02 07:30:58 +02:00
if ( index < 0 | | index > = size )
2009-01-31 20:29:27 +01:00
{
2011-02-02 17:12:46 +01:00
if ( index > size | | ! Token : : simpleMatch ( tok - > previous ( ) , " & ( " ) )
2009-10-06 13:50:27 +02:00
{
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( tok - > next ( ) , size , index ) ;
2009-10-06 13:50:27 +02:00
}
2009-01-31 20:29:27 +01:00
}
}
2010-08-04 20:38:52 +02:00
if ( Token : : Match ( tok , " return %varid% [ %num% ] " , varid ) )
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 3 ) ) ;
2010-08-04 20:38:52 +02:00
if ( index < 0 | | index > = size )
{
arrayIndexOutOfBounds ( tok - > next ( ) , size , index ) ;
}
}
2009-01-31 20:29:27 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( ! tok - > isName ( ) & & ! Token : : Match ( tok , " [.&] " ) & & Token : : Match ( tok - > next ( ) , ( varnames + " [ %num% ] " ) . c_str ( ) ) )
2009-01-31 20:29:27 +01:00
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 3 + varc ) ) ;
2010-04-18 20:51:39 +02:00
if ( index > = size )
2009-01-31 20:29:27 +01:00
{
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( tok - > tokAt ( 1 + varc ) , size , index ) ;
2009-01-31 20:29:27 +01:00
}
tok = tok - > tokAt ( 4 ) ;
continue ;
}
// memset, memcmp, memcpy, strncpy, fgets..
2010-10-26 20:05:34 +02:00
if ( varid = = 0 & & size > 0 )
2009-01-31 20:29:27 +01:00
{
2010-10-30 14:53:25 +02:00
ArrayInfo arrayInfo ( 0U ,
varnames ,
( unsigned int ) ( total_size / size ) ,
( unsigned int ) size ) ;
2010-04-21 20:02:58 +02:00
if ( Token : : Match ( tok , ( " %var% ( " + varnames + " , " ) . c_str ( ) ) )
2011-01-22 21:31:26 +01:00
checkFunctionParameter ( * tok , 1 , arrayInfo ) ;
2010-04-21 20:02:58 +02:00
if ( Token : : Match ( tok , ( " %var% ( %var% , " + varnames + " , " ) . c_str ( ) ) )
2011-01-22 21:31:26 +01:00
checkFunctionParameter ( * tok , 2 , arrayInfo ) ;
2009-01-31 20:29:27 +01:00
}
// Loop..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " for ( " ) )
2009-01-31 20:29:27 +01:00
{
2011-02-10 21:56:06 +01:00
const ArrayInfo arrayInfo ( varid , varnames , ( unsigned int ) size , ( unsigned int ) total_size ) ;
bool bailout = false ;
checkScopeForBody ( tok , arrayInfo , bailout ) ;
if ( bailout )
2009-10-01 10:33:53 +02:00
break ;
2009-01-31 20:29:27 +01:00
continue ;
}
// Writing data into array..
2010-04-02 07:30:58 +02:00
if ( ( varid > 0 & & Token : : Match ( tok , " strcpy|strcat ( %varid% , %str% ) " , varid ) ) | |
( varid = = 0 & & Token : : Match ( tok , ( " strcpy|strcat ( " + varnames + " , %str% ) " ) . c_str ( ) ) ) )
2009-01-31 20:29:27 +01:00
{
2010-12-31 09:30:56 +01:00
const std : : size_t len = Token : : getStrLength ( tok - > tokAt ( varc + 4 ) ) ;
2010-12-31 09:51:27 +01:00
if ( total_size > 0 & & len > = ( unsigned int ) total_size )
2009-01-31 20:29:27 +01:00
{
2010-02-21 15:23:50 +01:00
bufferOverrun ( tok , varid > 0 ? " " : varnames . c_str ( ) ) ;
2009-08-30 13:44:23 +02:00
continue ;
2009-01-31 20:29:27 +01:00
}
}
2011-08-21 20:44:55 +02:00
else if ( ( varid > 0 & & Token : : Match ( tok , " strcpy|strcat ( %varid% , %var% ) " , varid ) ) | |
( varid = = 0 & & Token : : Match ( tok , ( " strcpy|strcat ( " + varnames + " , %var% ) " ) . c_str ( ) ) ) )
{
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok - > tokAt ( 4 ) - > varId ( ) ) ;
if ( var & & var - > isArray ( ) & & var - > dimensions ( ) . size ( ) = = 1 )
{
const std : : size_t len = var - > dimension ( 0 ) ;
if ( total_size > 0 & & len > ( unsigned int ) total_size )
{
if ( _settings - > inconclusive )
2011-08-21 21:18:41 +02:00
possibleBufferOverrunError ( tok , tok - > strAt ( 4 ) , tok - > strAt ( 2 ) , tok - > str ( ) = = " strcat " ) ;
2011-08-21 20:44:55 +02:00
continue ;
}
}
}
2009-02-20 22:16:07 +01:00
2009-08-30 13:44:23 +02:00
// Detect few strcat() calls
2010-06-19 08:52:14 +02:00
const std : : string strcatPattern = varid > 0 ? std : : string ( " strcat ( %varid% , %str% ) ; " ) : ( " strcat ( " + varnames + " , %str% ) ; " ) ;
2010-05-29 07:51:28 +02:00
if ( Token : : Match ( tok , strcatPattern . c_str ( ) , varid ) )
2009-08-30 13:44:23 +02:00
{
size_t charactersAppend = 0 ;
const Token * tok2 = tok ;
2010-05-29 07:51:28 +02:00
while ( tok2 & & Token : : Match ( tok2 , strcatPattern . c_str ( ) , varid ) )
2009-08-30 13:44:23 +02:00
{
2010-05-29 07:51:28 +02:00
charactersAppend + = Token : : getStrLength ( tok2 - > tokAt ( 4 + varc ) ) ;
2010-04-02 07:30:58 +02:00
if ( charactersAppend > = static_cast < size_t > ( total_size ) )
2009-08-30 13:44:23 +02:00
{
bufferOverrun ( tok2 ) ;
break ;
}
2010-05-29 07:51:28 +02:00
tok2 = tok2 - > tokAt ( 7 + varc ) ;
2009-08-30 13:44:23 +02:00
}
}
2009-01-31 20:29:27 +01:00
2010-05-29 07:51:28 +02:00
// sprintf..
2010-08-06 21:02:43 +02:00
// TODO: change total_size to an unsigned value and remove the "&& total_size > 0" check.
2010-06-19 08:52:14 +02:00
const std : : string sprintfPattern = varid > 0 ? std : : string ( " sprintf ( %varid% , %str% [,)] " ) : ( " sprintf ( " + varnames + " , %str% [,)] " ) ;
2010-08-06 21:02:43 +02:00
if ( Token : : Match ( tok , sprintfPattern . c_str ( ) , varid ) & & total_size > 0 )
2009-01-31 20:29:27 +01:00
{
2010-08-06 21:02:43 +02:00
checkSprintfCall ( tok , static_cast < unsigned int > ( total_size ) ) ;
2010-05-29 07:51:28 +02:00
}
2009-01-31 20:29:27 +01:00
2010-05-29 07:51:28 +02:00
// snprintf..
2010-06-19 08:52:14 +02:00
const std : : string snprintfPattern = varid > 0 ? std : : string ( " snprintf ( %varid% , %num% , " ) : ( " snprintf ( " + varnames + " , %num% , " ) ;
2010-05-29 07:51:28 +02:00
if ( Token : : Match ( tok , snprintfPattern . c_str ( ) , varid ) )
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint n = MathLib : : toLongNumber ( tok - > strAt ( 4 + varc ) ) ;
2010-05-29 07:51:28 +02:00
if ( n > total_size )
outOfBounds ( tok - > tokAt ( 4 + varc ) , " snprintf size " ) ;
2009-02-21 13:22:04 +01:00
}
2009-01-31 20:29:27 +01:00
2011-01-22 21:31:26 +01:00
// Check function call..
2011-02-20 21:24:57 +01:00
if ( Token : : Match ( tok , " %var% ( " ) & & total_size > 0 )
2009-01-31 20:29:27 +01:00
{
2011-01-22 21:31:26 +01:00
// No varid => function calls are not handled
if ( varid = = 0 )
continue ;
const ArrayInfo arrayInfo ( varid , varnames , size , total_size / size ) ;
checkFunctionCall ( tok , arrayInfo ) ;
2009-01-31 20:29:27 +01:00
}
2011-01-01 20:56:21 +01:00
// undefined behaviour: result of pointer arithmetic is out of bounds
2011-01-04 18:34:51 +01:00
if ( varid & & Token : : Match ( tok , " = %varid% + %num% ; " , varid ) )
2011-01-01 20:56:21 +01:00
{
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 3 ) ) ;
2011-08-07 09:28:08 +02:00
if ( index > size & & _settings - > isEnabled ( " style " ) )
2011-01-01 20:56:21 +01:00
pointerOutOfBounds ( tok - > next ( ) , " buffer " ) ;
if ( index > = size & & Token : : Match ( tok - > tokAt ( - 2 ) , " [;{}] %varid% = " , varid ) )
pointerIsOutOfBounds = true ;
}
if ( pointerIsOutOfBounds & & Token : : Match ( tok , " [;{}=] * %varid% [;=] " , varid ) )
{
outOfBounds ( tok - > tokAt ( 2 ) , tok - > strAt ( 2 ) ) ;
}
2009-01-31 20:29:27 +01:00
}
}
2010-04-21 18:33:21 +02:00
void CheckBufferOverrun : : checkScope ( const Token * tok , const ArrayInfo & arrayInfo )
{
2011-06-23 02:35:58 +02:00
const MathLib : : bigint total_size = arrayInfo . num ( 0 ) * arrayInfo . element_size ( ) ;
2010-04-21 18:33:21 +02:00
2011-01-06 13:02:21 +01:00
// Count { and } for tok
2010-04-21 18:33:21 +02:00
unsigned int indentlevel = 0 ;
for ( ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
if ( indentlevel = = 0 )
return ;
- - indentlevel ;
}
2011-05-07 11:34:48 +02:00
// Skip array declarations
else if ( Token : : Match ( tok , " [;{}] %type% *| %var% [ " ) & &
tok - > strAt ( 1 ) ! = " return " )
{
tok = tok - > tokAt ( 3 ) ;
continue ;
}
2011-06-23 02:35:58 +02:00
else if ( Token : : Match ( tok , " %varid% [ %num% ] " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
2010-12-31 09:30:56 +01:00
std : : vector < MathLib : : bigint > indexes ;
2010-04-23 16:26:40 +02:00
for ( const Token * tok2 = tok - > next ( ) ; Token : : Match ( tok2 , " [ %num% ] " ) ; tok2 = tok2 - > tokAt ( 3 ) )
2010-04-21 18:33:21 +02:00
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok2 - > strAt ( 1 ) ) ;
2010-04-23 16:26:40 +02:00
if ( index < 0 )
{
indexes . clear ( ) ;
break ;
}
2010-12-31 09:30:56 +01:00
indexes . push_back ( index ) ;
2010-04-23 16:26:40 +02:00
}
2011-06-23 02:35:58 +02:00
if ( indexes . size ( ) = = arrayInfo . num ( ) . size ( ) )
2010-04-23 16:26:40 +02:00
{
// Check if the indexes point outside the whole array..
// char a[10][10];
// a[0][20] <-- ok.
// a[9][20] <-- error.
// total number of elements of array..
2010-12-31 09:30:56 +01:00
MathLib : : bigint totalElements = 1 ;
2010-04-23 16:26:40 +02:00
// total index..
2010-12-31 09:30:56 +01:00
MathLib : : bigint totalIndex = 0 ;
2010-04-23 16:26:40 +02:00
// calculate the totalElements and totalIndex..
for ( unsigned int i = 0 ; i < indexes . size ( ) ; + + i )
{
2010-12-31 09:30:56 +01:00
std : : size_t ri = indexes . size ( ) - 1 - i ;
2010-04-23 16:26:40 +02:00
totalIndex + = indexes [ ri ] * totalElements ;
2011-06-23 02:35:58 +02:00
totalElements * = arrayInfo . num ( ri ) ;
2010-04-23 16:26:40 +02:00
}
2011-08-05 13:08:48 +02:00
// totalElements == 0 => Unknown size
if ( totalElements = = 0 )
continue ;
2010-04-21 18:33:21 +02:00
// just taking the address?
const bool addr ( Token : : Match ( tok - > previous ( ) , " [.&] " ) | |
Token : : simpleMatch ( tok - > tokAt ( - 2 ) , " & ( " ) ) ;
2010-04-23 16:26:40 +02:00
// Is totalIndex in bounds?
if ( totalIndex > totalElements | | ( ! addr & & totalIndex = = totalElements ) )
{
arrayIndexOutOfBounds ( tok , arrayInfo , indexes ) ;
}
2010-04-21 18:33:21 +02:00
}
2010-04-23 16:26:40 +02:00
2010-04-21 18:33:21 +02:00
}
2010-05-17 19:51:35 +02:00
2010-04-21 18:33:21 +02:00
// Loop..
else if ( Token : : simpleMatch ( tok , " for ( " ) )
{
2011-02-10 21:56:06 +01:00
bool bailout = false ;
checkScopeForBody ( tok , arrayInfo , bailout ) ;
if ( bailout )
2010-04-21 18:33:21 +02:00
break ;
continue ;
}
2010-04-21 19:27:28 +02:00
// Check function call..
2010-04-24 21:48:58 +02:00
if ( Token : : Match ( tok , " %var% ( " ) )
{
2011-01-22 21:31:26 +01:00
checkFunctionCall ( tok , arrayInfo ) ;
2010-04-24 21:48:58 +02:00
}
2010-04-21 19:27:28 +02:00
2011-08-07 09:28:08 +02:00
if ( _settings - > isEnabled ( " style " ) )
2010-04-22 20:07:41 +02:00
{
// check for strncpy which is not terminated
2011-06-23 02:35:58 +02:00
if ( ( Token : : Match ( tok , " strncpy ( %varid% , %var% , %num% ) " , arrayInfo . varid ( ) ) ) )
2010-04-21 18:33:21 +02:00
{
2010-04-22 20:07:41 +02:00
// strncpy takes entire variable length as input size
if ( ( unsigned int ) MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) > = total_size )
2010-04-21 18:33:21 +02:00
{
2010-04-22 20:07:41 +02:00
const Token * tok2 = tok - > next ( ) - > link ( ) - > next ( ) ;
for ( ; tok2 ; tok2 = tok2 - > next ( ) )
2010-04-21 18:33:21 +02:00
{
2010-04-22 20:07:41 +02:00
if ( tok2 - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) )
2010-04-21 18:33:21 +02:00
{
2010-04-22 20:07:41 +02:00
if ( ! Token : : Match ( tok2 , " %varid% [ %any% ] = 0 ; " , tok - > tokAt ( 2 ) - > varId ( ) ) )
2010-04-21 18:33:21 +02:00
{
2011-04-10 15:55:08 +02:00
// this is currently 'experimental'. See TestBufferOverrun::terminateStrncpy3
if ( _settings - > experimental )
2010-11-07 09:37:45 +01:00
terminateStrncpyError ( tok ) ;
2010-04-21 18:33:21 +02:00
}
2010-04-22 20:07:41 +02:00
break ;
2010-04-21 18:33:21 +02:00
}
}
}
}
2010-04-22 20:07:41 +02:00
}
2010-04-21 18:33:21 +02:00
// Dangerous usage of strncat..
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok , " strncpy|strncat ( %varid% , %any% , %num% ) " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
if ( tok - > str ( ) = = " strncat " )
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint n = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) ;
2010-12-31 09:30:56 +01:00
if ( n > = total_size )
2010-04-21 18:33:21 +02:00
strncatUsage ( tok ) ;
}
// Dangerous usage of strncpy + strncat..
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 8 ) , " ; strncat ( %varid% , %any% , %num% ) " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint n = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) + MathLib : : toLongNumber ( tok - > strAt ( 15 ) ) ;
2010-12-31 09:30:56 +01:00
if ( n > total_size )
2010-04-21 18:33:21 +02:00
strncatUsage ( tok - > tokAt ( 9 ) ) ;
}
}
// Writing data into array..
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok , " strcpy|strcat ( %varid% , %str% ) " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
2010-12-31 09:30:56 +01:00
const std : : size_t len = Token : : getStrLength ( tok - > tokAt ( 4 ) ) ;
2010-12-31 09:51:27 +01:00
if ( total_size > 0 & & len > = ( unsigned int ) total_size )
2010-04-21 18:33:21 +02:00
{
2011-06-23 02:35:58 +02:00
bufferOverrun ( tok , arrayInfo . varname ( ) ) ;
2010-04-21 18:33:21 +02:00
continue ;
}
}
// Detect few strcat() calls
2011-06-23 02:35:58 +02:00
if ( total_size > 0 & & Token : : Match ( tok , " strcat ( %varid% , %str% ) ; " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
2010-12-31 09:30:56 +01:00
std : : size_t charactersAppend = 0 ;
2010-04-21 18:33:21 +02:00
const Token * tok2 = tok ;
2011-06-23 02:35:58 +02:00
while ( tok2 & & Token : : Match ( tok2 , " strcat ( %varid% , %str% ) ; " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
charactersAppend + = Token : : getStrLength ( tok2 - > tokAt ( 4 ) ) ;
2010-12-31 09:51:27 +01:00
if ( charactersAppend > = ( unsigned int ) total_size )
2010-04-21 18:33:21 +02:00
{
2011-06-23 02:35:58 +02:00
bufferOverrun ( tok2 , arrayInfo . varname ( ) ) ;
2010-04-21 18:33:21 +02:00
break ;
}
tok2 = tok2 - > tokAt ( 7 ) ;
}
}
2011-06-23 02:35:58 +02:00
if ( Token : : Match ( tok , " sprintf ( %varid% , %str% [,)] " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
checkSprintfCall ( tok , total_size ) ;
}
// snprintf..
2011-06-23 02:35:58 +02:00
if ( total_size > 0 & & Token : : Match ( tok , " snprintf ( %varid% , %num% , " , arrayInfo . varid ( ) ) )
2010-04-21 18:33:21 +02:00
{
2010-11-20 11:48:03 +01:00
const MathLib : : bigint n = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
2010-12-31 09:30:56 +01:00
if ( n > total_size )
2010-04-21 18:33:21 +02:00
outOfBounds ( tok - > tokAt ( 4 ) , " snprintf size " ) ;
}
2010-12-26 21:23:28 +01:00
// undefined behaviour: result of pointer arithmetic is out of bounds
2011-08-07 09:28:08 +02:00
if ( _settings - > isEnabled ( " style " ) & & Token : : Match ( tok , " = %varid% + %num% ; " , arrayInfo . varid ( ) ) )
2010-12-26 21:23:28 +01:00
{
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > strAt ( 3 ) ) ;
2011-06-23 02:35:58 +02:00
if ( index < 0 | | index > arrayInfo . num ( 0 ) )
2010-12-26 21:23:28 +01:00
{
2011-01-01 20:56:21 +01:00
pointerOutOfBounds ( tok - > next ( ) , " array " ) ;
2010-12-26 21:23:28 +01:00
}
}
2010-04-21 18:33:21 +02:00
}
}
2009-01-31 20:29:27 +01:00
//---------------------------------------------------------------------------
// 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
{
2011-06-24 14:02:41 +02:00
// check all known fixed size arrays first by just looking them up
for ( size_t i = 1 ; i < = _tokenizer - > varIdCount ( ) ; i + + )
{
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( i ) ;
if ( var & & var - > isArray ( ) & & var - > dimension ( 0 ) > 0 )
{
ArrayInfo arrayInfo ( var , _tokenizer ) ;
const Token * tok = var - > nameToken ( ) ;
while ( tok & & tok - > str ( ) ! = " ; " )
2011-08-07 17:54:25 +02:00
{
if ( tok - > str ( ) = = " { " )
{
if ( Token : : simpleMatch ( tok - > previous ( ) , " = { " ) )
tok = tok - > link ( ) ;
else
break ;
}
2011-06-24 14:02:41 +02:00
tok = tok - > next ( ) ;
2011-08-07 17:54:25 +02:00
}
2011-06-24 14:02:41 +02:00
if ( ! tok )
break ;
2011-08-07 17:54:25 +02:00
if ( tok - > str ( ) = = " { " )
tok = tok - > next ( ) ;
2011-06-24 14:02:41 +02:00
checkScope ( tok , arrayInfo ) ;
}
}
// find all dynamically allocated arrays next by parsing the token stream
2011-01-06 13:02:21 +01:00
// Count { and } when parsing all tokens
2009-01-31 20:29:27 +01:00
int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-31 20:29:27 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-31 20:29:27 +01:00
- - indentlevel ;
2011-01-06 13:02:21 +01:00
// size : Max array index
2010-11-21 11:48:27 +01:00
MathLib : : bigint size = 0 ;
2011-01-06 13:02:21 +01:00
// type : The type of a array element
2010-02-14 19:58:17 +01:00
std : : string type ;
2011-01-06 13:02:21 +01:00
// varid : The variable id for the array
2009-02-11 17:12:29 +01:00
unsigned int varid = 0 ;
2011-01-06 13:02:21 +01:00
// nextTok : number of tokens used in variable declaration - used to skip to next statement.
2009-02-11 17:12:29 +01:00
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 "[;{}]"
2010-04-02 07:30:58 +02:00
if ( tok - > previous ( ) & & ( ! tok - > previous ( ) - > isName ( ) & & ! Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) )
2009-06-02 18:56:53 +02:00
continue ;
2010-07-24 20:54:42 +02:00
2010-08-03 16:36:21 +02:00
_errorLogger - > reportProgress ( _tokenizer - > getFiles ( ) - > front ( ) ,
" Check (BufferOverrun::checkGlobalAndLocalVariable) " ,
tok - > progressValue ( ) ) ;
2009-06-02 18:56:53 +02:00
2011-06-24 14:02:41 +02:00
if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = new %type% [ %num% ] " ) )
2009-02-11 17:12:29 +01:00
{
2010-02-14 19:58:17 +01:00
size = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) ;
2009-02-11 17:12:29 +01:00
type = tok - > strAt ( 4 ) ;
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 8 ;
}
2010-04-02 07:30:58 +02:00
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = new %type% ( %num% ) " ) )
2009-11-15 13:02:03 +01:00
{
size = 1 ;
type = tok - > strAt ( 4 ) ;
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 8 ;
}
2010-10-22 20:15:51 +02:00
else if ( indentlevel > 0 & &
Token : : Match ( tok , " [;{}] %var% = %str% ; " ) & &
2010-10-26 18:10:03 +02:00
tok - > next ( ) - > varId ( ) > 0 & &
2010-10-22 20:15:51 +02:00
NULL ! = Token : : findmatch ( _tokenizer - > tokens ( ) , " [;{}] const| %type% * %varid% ; " , tok - > next ( ) - > varId ( ) ) )
2010-10-10 09:15:18 +02:00
{
2010-10-11 20:52:14 +02:00
size = 1 + int ( tok - > tokAt ( 3 ) - > strValue ( ) . size ( ) ) ;
2010-10-10 09:15:18 +02:00
type = " char " ;
varid = tok - > next ( ) - > varId ( ) ;
nextTok = 4 ;
}
2011-07-17 09:35:51 +02:00
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = malloc|alloca ( %num% ) ; " ) )
2009-03-16 18:11:09 +01:00
{
2010-02-14 19:58:17 +01:00
size = MathLib : : toLongNumber ( tok - > strAt ( 5 ) ) ;
2010-04-10 07:57:29 +02:00
type = " char " ; // minimum type, typesize=1
2009-03-16 18:11:09 +01:00
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 7 ;
2009-11-15 13:38:57 +01:00
2010-04-10 07:57:29 +02:00
if ( varid > 0 )
2009-11-15 13:38:57 +01:00
{
2010-04-10 07:57:29 +02:00
// get type of variable
2011-06-23 05:11:17 +02:00
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( varid ) ;
/** @todo false negatives: this may be too conservative */
if ( ! var | | var - > typeEndToken ( ) - > str ( ) ! = " * " | | var - > typeStartToken ( ) - > next ( ) ! = var - > typeEndToken ( ) )
2010-04-11 20:57:30 +02:00
continue ;
2011-06-23 05:11:17 +02:00
// get name of variable
type = var - > typeStartToken ( ) - > str ( ) ;
2010-04-10 07:57:29 +02:00
2009-11-15 13:38:57 +01:00
// malloc() gets count of bytes and not count of
// elements, so we should calculate count of elements
// manually
2011-06-23 05:11:17 +02:00
unsigned int sizeOfType = _tokenizer - > sizeOfType ( var - > typeStartToken ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( sizeOfType > 0 )
2010-08-06 21:02:43 +02:00
size / = static_cast < int > ( sizeOfType ) ;
2009-11-15 13:38:57 +01:00
}
2009-03-16 18:11:09 +01:00
}
2009-02-11 17:12:29 +01:00
else
{
continue ;
}
2009-01-31 20:29:27 +01:00
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-11-06 23:58:33 +01:00
continue ;
2010-01-06 20:19:27 +01:00
Token sizeTok ( 0 ) ;
2009-10-07 09:54:34 +02:00
sizeTok . str ( type ) ;
2010-11-21 11:48:27 +01:00
const MathLib : : bigint total_size = size * static_cast < int > ( _tokenizer - > sizeOfType ( & sizeTok ) ) ;
2010-04-02 07:30:58 +02:00
if ( total_size = = 0 )
2009-02-11 17:12:29 +01:00
continue ;
2009-01-31 20:29:27 +01:00
2010-02-14 19:58:17 +01:00
std : : vector < std : : string > v ;
checkScope ( tok - > tokAt ( nextTok ) , v , 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
{
2010-08-24 22:03:18 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-08-24 22:03:18 +02:00
if ( tok - > str ( ) = = " { " )
{
tok = tok - > link ( ) ;
}
if ( ! Token : : Match ( tok , " struct|class %var% {|: " ) )
continue ;
2009-01-31 20:29:27 +01:00
const std : : string & structname = tok - > next ( ) - > str ( ) ;
2010-06-13 07:17:50 +02:00
const Token * tok2 = tok ;
2011-02-19 20:38:00 +01:00
while ( tok2 & & tok2 - > str ( ) ! = " { " )
2010-06-13 07:17:50 +02:00
tok2 = tok2 - > next ( ) ;
2009-01-31 20:29:27 +01:00
// Found a struct declaration. Search for arrays..
2010-06-13 07:17:50 +02:00
for ( ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-04-08 19:57:38 +02:00
// skip inner scopes..
if ( tok2 - > next ( ) & & tok2 - > next ( ) - > str ( ) = = " { " )
{
tok2 = tok2 - > next ( ) - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " } " )
2009-01-31 20:29:27 +01:00
break ;
2010-04-18 20:06:54 +02:00
ArrayInfo arrayInfo ;
if ( ! arrayInfo . declare ( tok2 - > next ( ) , * _tokenizer ) )
2009-01-31 20:29:27 +01:00
continue ;
2010-04-18 20:06:54 +02:00
// Only handling 1-dimensional arrays yet..
2011-06-23 02:35:58 +02:00
if ( arrayInfo . num ( ) . size ( ) > 1 )
2009-01-31 20:29:27 +01:00
continue ;
2010-11-06 09:10:10 +01:00
// Skip array with only 0/1 elements because those are
// often overrun intentionally
2011-06-23 02:35:58 +02:00
if ( arrayInfo . num ( 0 ) < = 1 )
2010-11-06 09:10:10 +01:00
continue ;
2009-01-31 20:29:27 +01:00
2010-04-18 20:06:54 +02:00
std : : vector < std : : string > varname ;
varname . push_back ( " " ) ;
2011-06-23 02:35:58 +02:00
varname . push_back ( arrayInfo . varname ( ) ) ;
2009-01-31 20:29:27 +01:00
// Class member variable => Check functions
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " class " )
2009-01-31 20:29:27 +01:00
{
std : : string func_pattern ( structname + " :: %var% ( " ) ;
const Token * tok3 = Token : : findmatch ( _tokenizer - > tokens ( ) , func_pattern . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
while ( tok3 )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok4 , " [;{}] " ) )
2009-01-31 20:29:27 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok4 , " ) { " ) )
2009-01-31 20:29:27 +01:00
{
2010-02-14 19:58:17 +01:00
std : : vector < std : : string > v ;
2011-06-23 02:35:58 +02:00
checkScope ( tok4 - > tokAt ( 2 ) , v , static_cast < int > ( arrayInfo . num ( 0 ) ) , static_cast < int > ( arrayInfo . num ( 0 ) * arrayInfo . element_size ( ) ) , arrayInfo . varid ( ) ) ;
2009-01-31 20:29:27 +01:00
break ;
}
}
tok3 = Token : : findmatch ( tok3 - > next ( ) , func_pattern . c_str ( ) ) ;
}
}
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = _tokenizer - > tokens ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) ! = structname )
2009-01-31 20:29:27 +01:00
continue ;
// Declare variable: Fred fred1;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok3 - > next ( ) , " %var% ; " ) )
2009-01-31 20:29:27 +01:00
varname [ 0 ] = tok3 - > strAt ( 1 ) ;
// Declare pointer: Fred *fred1
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 - > next ( ) , " * %var% [,) ; = ] " ))
2009-01-31 20:29:27 +01:00
varname [ 0 ] = tok3 - > strAt ( 2 ) ;
else
continue ;
// Goto end of statement.
const Token * CheckTok = NULL ;
2010-04-02 07:30:58 +02:00
while ( tok3 )
2009-01-31 20:29:27 +01:00
{
// End of statement.
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " ; " )
2009-01-31 20:29:27 +01:00
{
CheckTok = tok3 ;
break ;
}
// End of function declaration..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok3 , " ) ; " ) )
2009-01-31 20:29:27 +01:00
break ;
// Function implementation..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok3 , " ) { " ) )
2009-01-31 20:29:27 +01:00
{
CheckTok = tok3 - > tokAt ( 2 ) ;
break ;
}
tok3 = tok3 - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( ! tok3 )
2009-01-31 20:29:27 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( ! CheckTok )
2009-01-31 20:29:27 +01:00
continue ;
// Check variable usage..
2011-06-23 02:35:58 +02:00
checkScope ( CheckTok , varname , static_cast < int > ( arrayInfo . num ( 0 ) ) , static_cast < int > ( arrayInfo . num ( 0 ) * arrayInfo . element_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 ( ) ;
2010-05-26 10:56:34 +02:00
checkBufferAllocatedWithStrlen ( ) ;
2010-06-02 07:41:07 +02:00
checkInsecureCmdLineArgs ( ) ;
2009-01-31 20:29:27 +01:00
}
//---------------------------------------------------------------------------
2010-12-31 09:30:56 +01:00
MathLib : : bigint CheckBufferOverrun : : countSprintfLength ( const std : : string & input_string , const std : : list < const Token * > & parameters )
2009-09-25 18:23:44 +02:00
{
2009-10-18 12:58:48 +02:00
bool percentCharFound = false ;
2010-12-31 09:30:56 +01:00
std : : size_t input_string_size = 1 ;
2009-10-18 12:58:48 +02:00
bool handleNextParameter = false ;
2009-09-25 18:23:44 +02:00
std : : string digits_string = " " ;
2009-10-18 12:58:48 +02:00
bool i_d_x_f_found = false ;
2009-10-08 15:27:46 +02:00
std : : list < const Token * > : : const_iterator paramIter = parameters . begin ( ) ;
2010-12-31 09:30:56 +01:00
std : : size_t parameterLength = 0 ;
2010-04-02 07:30:58 +02:00
for ( std : : string : : size_type i = 0 ; i < input_string . length ( ) ; + + i )
2009-09-25 18:23:44 +02:00
{
2010-04-02 07:30:58 +02:00
if ( input_string [ i ] = = ' \\ ' )
2009-09-25 18:23:44 +02:00
{
2010-04-02 07:30:58 +02:00
if ( input_string [ i + 1 ] = = ' 0 ' )
2009-10-18 12:58:48 +02:00
break ;
+ + input_string_size ;
+ + i ;
continue ;
2009-09-25 18:23:44 +02:00
}
2009-10-18 12:58:48 +02:00
2010-04-02 07:30:58 +02:00
if ( percentCharFound )
2009-09-25 18:23:44 +02:00
{
2010-04-02 07:30:58 +02:00
switch ( input_string [ i ] )
2009-10-08 15:27:46 +02:00
{
2009-10-18 12:58:48 +02:00
case ' f ' :
case ' x ' :
case ' X ' :
case ' i ' :
i_d_x_f_found = true ;
case ' c ' :
case ' e ' :
case ' E ' :
case ' g ' :
case ' o ' :
case ' u ' :
case ' p ' :
case ' n ' :
2009-10-19 23:48:29 +02:00
handleNextParameter = true ;
break ;
case ' d ' :
i_d_x_f_found = true ;
2010-04-02 07:30:58 +02:00
if ( paramIter ! = parameters . end ( ) & & * paramIter & & ( * paramIter ) - > str ( ) [ 0 ] ! = ' " ' )
2010-03-09 11:03:45 +01:00
parameterLength = ( * paramIter ) - > str ( ) . length ( ) ;
2009-10-19 23:48:29 +02:00
2009-10-18 12:58:48 +02:00
handleNextParameter = true ;
break ;
case ' s ' :
2010-04-02 07:30:58 +02:00
if ( paramIter ! = parameters . end ( ) & & * paramIter & & ( * paramIter ) - > str ( ) [ 0 ] = = ' " ' )
2010-03-09 11:03:45 +01:00
parameterLength = Token : : getStrLength ( * paramIter ) ;
2009-10-08 15:27:46 +02:00
2009-10-18 12:58:48 +02:00
handleNextParameter = true ;
break ;
2009-10-08 15:27:46 +02:00
}
2009-10-18 12:58:48 +02:00
}
2009-10-08 15:27:46 +02:00
2010-04-02 07:30:58 +02:00
if ( input_string [ i ] = = ' % ' )
2009-10-18 12:58:48 +02:00
percentCharFound = ! percentCharFound ;
2010-04-02 07:30:58 +02:00
else if ( percentCharFound )
2009-10-18 12:58:48 +02:00
{
digits_string . append ( 1 , input_string [ i ] ) ;
2009-09-25 18:23:44 +02:00
}
2010-04-02 07:30:58 +02:00
if ( ! percentCharFound )
2009-10-18 12:58:48 +02:00
input_string_size + + ;
2009-09-25 18:23:44 +02:00
2010-04-02 07:30:58 +02:00
if ( handleNextParameter )
2009-09-25 18:23:44 +02:00
{
2010-08-06 21:02:43 +02:00
unsigned int tempDigits = static_cast < unsigned int > ( std : : abs ( std : : atoi ( digits_string . c_str ( ) ) ) ) ;
2010-04-02 07:30:58 +02:00
if ( i_d_x_f_found )
2010-08-06 21:02:43 +02:00
tempDigits = std : : max ( static_cast < unsigned int > ( tempDigits ) , 1U ) ;
2009-10-08 15:27:46 +02:00
2010-04-02 07:30:58 +02:00
if ( digits_string . find ( ' . ' ) ! = std : : string : : npos )
2009-10-11 21:07:18 +02:00
{
const std : : string endStr = digits_string . substr ( digits_string . find ( ' . ' ) + 1 ) ;
2010-08-06 21:02:43 +02:00
unsigned int maxLen = std : : max ( static_cast < unsigned int > ( std : : abs ( std : : atoi ( endStr . c_str ( ) ) ) ) , 1U ) ;
2009-10-11 21:07:18 +02:00
2010-04-02 07:30:58 +02:00
if ( input_string [ i ] = = ' s ' )
2009-10-19 23:48:29 +02:00
{
// For strings, the length after the dot "%.2s" will limit
// the length of the string.
2010-04-02 07:30:58 +02:00
if ( parameterLength > maxLen )
2009-10-19 23:48:29 +02:00
parameterLength = maxLen ;
}
else
{
// For integers, the length after the dot "%.2d" can
// increase required length
2010-04-02 07:30:58 +02:00
if ( tempDigits < maxLen )
2009-10-19 23:48:29 +02:00
tempDigits = maxLen ;
}
2009-10-11 21:07:18 +02:00
}
2010-04-02 07:30:58 +02:00
if ( tempDigits < parameterLength )
2009-10-18 12:58:48 +02:00
input_string_size + = parameterLength ;
2009-10-08 15:27:46 +02:00
else
2009-10-19 23:48:29 +02:00
input_string_size + = tempDigits ;
2009-10-08 15:27:46 +02:00
parameterLength = 0 ;
2009-09-26 16:19:18 +02:00
digits_string = " " ;
2009-10-18 12:58:48 +02:00
i_d_x_f_found = false ;
percentCharFound = false ;
handleNextParameter = false ;
2010-04-02 07:30:58 +02:00
if ( paramIter ! = parameters . end ( ) )
2009-10-19 23:55:20 +02:00
+ + paramIter ;
2009-09-25 18:23:44 +02:00
}
}
2010-12-31 09:51:27 +01:00
return ( MathLib : : bigint ) input_string_size ;
2009-09-25 18:23:44 +02:00
}
2010-12-31 09:30:56 +01:00
void CheckBufferOverrun : : checkSprintfCall ( const Token * tok , const MathLib : : bigint size )
2009-10-07 14:37:20 +02:00
{
2010-10-19 18:23:44 +02:00
if ( size = = 0 )
return ;
2010-05-29 07:51:28 +02:00
const Token * end = tok - > next ( ) - > link ( ) ;
2010-05-29 11:19:56 +02:00
2010-05-29 07:51:28 +02:00
// Count the number of tokens in the buffer variable's name
int varc = 0 ;
for ( const Token * tok1 = tok - > tokAt ( 3 ) ; tok1 ! = end ; tok1 = tok1 - > next ( ) )
{
if ( tok1 - > str ( ) = = " , " )
break ;
+ + varc ;
}
2010-05-29 11:19:56 +02:00
2009-10-11 20:36:22 +02:00
std : : list < const Token * > parameters ;
2010-05-29 07:51:28 +02:00
if ( tok - > tokAt ( 5 + varc ) - > str ( ) = = " , " )
2009-10-07 14:37:20 +02:00
{
2010-05-29 07:51:28 +02:00
for ( const Token * tok2 = tok - > tokAt ( 5 + varc ) ; tok2 & & tok2 ! = end ; tok2 = tok2 - > next ( ) )
2009-10-07 14:37:20 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " , %any% [,)] " ) )
2009-10-07 14:37:20 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " %str% " ) )
2009-10-11 20:36:22 +02:00
parameters . push_back ( tok2 - > next ( ) ) ;
2009-10-07 14:37:20 +02:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " %num% " ) )
2009-10-11 20:36:22 +02:00
parameters . push_back ( tok2 - > next ( ) ) ;
2009-10-07 14:37:20 +02:00
else
parameters . push_back ( 0 ) ;
}
2009-10-11 20:36:22 +02:00
else
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
// Parameter is more complex, than just a value or variable. Ignore it for now
// and skip to next token.
parameters . push_back ( 0 ) ;
2011-01-06 13:02:21 +01:00
2011-03-30 16:45:31 +02:00
// count parentheses for tok3
2009-10-11 20:36:22 +02:00
int ind = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = tok2 - > next ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-10-07 14:37:20 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " ( " )
2009-10-11 20:36:22 +02:00
+ + ind ;
2009-10-07 14:37:20 +02:00
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " ) " )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
- - ind ;
2010-04-02 07:30:58 +02:00
if ( ind < 0 )
2009-10-11 20:36:22 +02:00
break ;
2009-10-07 14:37:20 +02:00
}
2009-10-11 20:36:22 +02:00
2010-04-02 07:30:58 +02:00
else if ( ind = = 0 & & tok3 - > str ( ) = = " , " )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
tok2 = tok3 - > previous ( ) ;
break ;
2009-10-07 14:37:20 +02:00
}
}
2009-10-11 20:36:22 +02:00
2010-04-02 07:30:58 +02:00
if ( ind < 0 )
2009-10-11 20:36:22 +02:00
break ;
2009-10-07 14:37:20 +02:00
}
}
}
2009-10-11 20:36:22 +02:00
2010-12-31 09:30:56 +01:00
MathLib : : bigint len = countSprintfLength ( tok - > tokAt ( 4 + varc ) - > strValue ( ) , parameters ) ;
2010-04-02 07:30:58 +02:00
if ( len > size )
2009-10-11 20:36:22 +02:00
{
bufferOverrun ( tok ) ;
}
2009-10-07 14:37:20 +02:00
}
2010-04-10 21:12:00 +02:00
2010-05-26 10:56:34 +02:00
//---------------------------------------------------------------------------
// Checking for allocating insufficient memory for copying a string by
// allocating only strlen(src) bytes instead of strlen(src) + 1 bytes (one
// extra for the terminating null character).
// Example:
// char *b = malloc(strlen(a)); // Should be malloc(strlen(a) + 1);
// strcpy(b, a); // <== Buffer overrun
//---------------------------------------------------------------------------
void CheckBufferOverrun : : checkBufferAllocatedWithStrlen ( )
{
const char pattern [ ] = " %var% = new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc " ;
for ( const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern ) ; tok ; tok = Token : : findmatch ( tok - > next ( ) , pattern ) )
{
unsigned int dstVarId ;
unsigned int srcVarId ;
2010-05-26 19:21:34 +02:00
2010-05-26 10:56:34 +02:00
// Look for allocation of a buffer based on the size of a string
if ( Token : : Match ( tok , " %var% = malloc|g_malloc|g_try_malloc ( strlen ( %var% ) ) " ) )
{
dstVarId = tok - > varId ( ) ;
srcVarId = tok - > tokAt ( 6 ) - > varId ( ) ;
tok = tok - > tokAt ( 8 ) ;
}
else if ( Token : : Match ( tok , " %var% = new char [ strlen ( %var% ) ] " ) )
{
dstVarId = tok - > varId ( ) ;
srcVarId = tok - > tokAt ( 7 ) - > varId ( ) ;
tok = tok - > tokAt ( 9 ) ;
}
else if ( Token : : Match ( tok , " %var% = realloc|g_realloc|g_try_realloc ( %var% , strlen ( %var% ) ) " ) )
{
dstVarId = tok - > varId ( ) ;
srcVarId = tok - > tokAt ( 8 ) - > varId ( ) ;
tok = tok - > tokAt ( 10 ) ;
}
else
continue ;
2010-05-26 19:21:34 +02:00
2011-01-06 13:02:21 +01:00
// count { and } for tok
2010-05-26 10:56:34 +02:00
int indentlevel = 0 ;
for ( ; tok & & tok - > next ( ) ; tok = tok - > next ( ) )
{
// To avoid false positives and added complexity, we will only look for
// improper usage of the buffer within the block that it was allocated
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < 0 )
return ;
}
2010-05-26 19:21:34 +02:00
2010-05-26 10:56:34 +02:00
// If the buffers are modified, we can't be sure of their sizes
if ( tok - > varId ( ) = = srcVarId | | tok - > varId ( ) = = dstVarId )
break ;
2010-05-26 19:21:34 +02:00
2010-05-26 10:56:34 +02:00
if ( Token : : Match ( tok , " strcpy ( %varid% , %var% ) " , dstVarId ) & &
tok - > tokAt ( 4 ) - > varId ( ) = = srcVarId )
{
bufferOverrun ( tok ) ;
}
else if ( Token : : Match ( tok , " sprintf ( %varid% , %str% , %var% ) " , dstVarId ) & &
2010-05-26 19:21:34 +02:00
tok - > tokAt ( 6 ) - > varId ( ) = = srcVarId & &
tok - > tokAt ( 4 ) - > str ( ) . find ( " %s " ) ! = std : : string : : npos )
2010-05-26 10:56:34 +02:00
{
bufferOverrun ( tok ) ;
}
2010-05-26 19:21:34 +02:00
2010-05-26 10:56:34 +02:00
}
2010-05-26 19:21:34 +02:00
2010-05-26 10:56:34 +02:00
}
}
2010-06-02 07:41:07 +02:00
//---------------------------------------------------------------------------
// Checking for buffer overflow caused by copying command line arguments
// into fixed-sized buffers without checking to make sure that the command
// line arguments will not overflow the buffer.
//
// int main(int argc, char* argv[])
// {
// char prog[10];
// strcpy(prog, argv[0]); <-- Possible buffer overrun
// }
//---------------------------------------------------------------------------
void CheckBufferOverrun : : checkInsecureCmdLineArgs ( )
{
const char pattern [ ] = " main ( int %var% , char * " ;
for ( const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern ) ; tok ; tok = Token : : findmatch ( tok - > next ( ) , pattern ) )
{
// Get the name of the argv variable
unsigned int varid = 0 ;
if ( Token : : Match ( tok , " main ( int %var% , char * %var% [ ] ,|) " ) )
{
varid = tok - > tokAt ( 7 ) - > varId ( ) ;
}
else if ( Token : : Match ( tok , " main ( int %var% , char * * %var% ,|) " ) )
{
varid = tok - > tokAt ( 8 ) - > varId ( ) ;
}
if ( varid = = 0 )
continue ;
2010-06-02 18:09:25 +02:00
2010-06-02 07:41:07 +02:00
// Jump to the opening curly brace
tok = tok - > next ( ) - > link ( ) ;
2010-06-04 07:42:54 +02:00
if ( ! Token : : simpleMatch ( tok , " ) { " ) )
2010-06-02 07:41:07 +02:00
continue ;
tok = tok - > next ( ) ;
2010-06-02 18:09:25 +02:00
2010-06-02 07:41:07 +02:00
// Search within main() for possible buffer overruns involving argv
int indentlevel = - 1 ;
2010-06-04 07:42:54 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2010-06-02 07:41:07 +02:00
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < 0 )
return ;
}
// If argv is modified or tested, its size may be being limited properly
if ( tok - > varId ( ) = = varid )
break ;
// Match common patterns that can result in a buffer overrun
// e.g. strcpy(buffer, argv[0])
if ( Token : : Match ( tok , " strcpy|strcat ( %var% , * %varid% " , varid ) | |
Token : : Match ( tok , " strcpy|strcat ( %var% , %varid% [ " , varid ) )
{
cmdLineArgsError ( tok ) ;
}
else if ( Token : : Match ( tok , " sprintf ( %var% , %str% , %varid% [ " , varid ) & &
2010-06-02 18:09:25 +02:00
tok - > tokAt ( 4 ) - > str ( ) . find ( " %s " ) ! = std : : string : : npos )
2010-06-02 07:41:07 +02:00
{
cmdLineArgsError ( tok ) ;
}
else if ( Token : : Match ( tok , " sprintf ( %var% , %str% , * %varid% " , varid ) & &
2010-06-02 18:09:25 +02:00
tok - > tokAt ( 4 ) - > str ( ) . find ( " %s " ) ! = std : : string : : npos )
2010-06-02 07:41:07 +02:00
{
cmdLineArgsError ( tok ) ;
}
2010-06-02 18:09:25 +02:00
2010-06-02 07:41:07 +02:00
}
}
}
2010-05-26 10:56:34 +02:00
//---------------------------------------------------------------------------
2010-11-21 11:48:27 +01:00
void CheckBufferOverrun : : negativeIndexError ( const Token * tok , MathLib : : bigint index )
2010-04-18 20:51:39 +02:00
{
2010-04-18 21:03:03 +02:00
std : : ostringstream ostr ;
2010-04-20 20:44:31 +02:00
ostr < < " Array index " < < index < < " is out of bounds " ;
2010-04-18 21:03:03 +02:00
reportError ( tok , Severity : : error , " negativeIndex " , ostr . str ( ) ) ;
2010-04-18 20:51:39 +02:00
}
void CheckBufferOverrun : : negativeIndex ( )
{
2010-04-18 21:03:03 +02:00
const char pattern [ ] = " [ %num% ] " ;
for ( const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern ) ; tok ; tok = Token : : findmatch ( tok - > next ( ) , pattern ) )
{
2010-11-21 11:48:27 +01:00
const MathLib : : bigint index = MathLib : : toLongNumber ( tok - > next ( ) - > str ( ) ) ;
2010-04-18 21:03:03 +02:00
if ( index < 0 )
{
2010-07-14 12:24:07 +02:00
// Negative index. Check if it's an array.
const Token * tok2 = tok ;
while ( Token : : simpleMatch ( tok2 - > previous ( ) , " ] " ) )
tok2 = tok2 - > previous ( ) - > link ( ) ;
2010-04-20 16:43:51 +02:00
2010-07-14 12:24:07 +02:00
if ( tok2 - > previous ( ) & & tok2 - > previous ( ) - > varId ( ) )
2010-04-20 16:43:51 +02:00
{
2011-06-23 05:11:17 +02:00
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok2 - > previous ( ) - > varId ( ) ) ;
if ( var & & var - > isArray ( ) )
2010-04-20 16:43:51 +02:00
negativeIndexError ( tok , index ) ;
}
2010-04-18 21:03:03 +02:00
}
}
2010-04-18 20:51:39 +02:00
}
2010-04-10 21:12:00 +02:00
# include "executionpath.h"
/// @addtogroup Checks
/// @{
2010-04-18 11:08:29 +02:00
CheckBufferOverrun : : ArrayInfo : : ArrayInfo ( )
2010-04-10 21:12:00 +02:00
{
2010-04-18 20:18:25 +02:00
_element_size = 0 ;
2010-04-18 19:46:45 +02:00
_varid = 0 ;
2010-04-18 11:08:29 +02:00
}
CheckBufferOverrun : : ArrayInfo : : ArrayInfo ( const CheckBufferOverrun : : ArrayInfo & ai )
{
* this = ai ;
}
2011-06-23 04:44:11 +02:00
CheckBufferOverrun : : ArrayInfo : : ArrayInfo ( const Variable * var , const Tokenizer * tokenizer )
{
_varid = var - > varId ( ) ;
_varname = var - > name ( ) ;
for ( size_t i = 0 ; i < var - > dimensions ( ) . size ( ) ; i + + )
_num . push_back ( var - > dimension ( i ) ) ;
if ( var - > typeEndToken ( ) - > str ( ) = = " * " )
_element_size = tokenizer - > sizeOfType ( var - > typeEndToken ( ) ) ;
else if ( var - > typeStartToken ( ) - > str ( ) = = " struct " )
_element_size = 100 ;
else
_element_size = tokenizer - > sizeOfType ( var - > typeEndToken ( ) ) ;
}
2010-09-15 22:25:12 +02:00
CheckBufferOverrun : : ArrayInfo & CheckBufferOverrun : : ArrayInfo : : operator = ( const CheckBufferOverrun : : ArrayInfo & ai )
2010-04-18 11:08:29 +02:00
{
if ( & ai ! = this )
{
2011-06-23 02:35:58 +02:00
_element_size = ai . _element_size ;
_num = ai . _num ;
_varid = ai . _varid ;
_varname = ai . _varname ;
2010-04-18 11:08:29 +02:00
}
return * this ;
}
2010-04-21 18:33:21 +02:00
/**
* Create array info with specified data
* The intention is that this is only a temporary solution . . all
* checking should be based on ArrayInfo from the start and then
* this will not be needed as the declare can be used instead .
*/
2010-12-31 09:30:56 +01:00
CheckBufferOverrun : : ArrayInfo : : ArrayInfo ( unsigned int id , const std : : string & name , MathLib : : bigint size1 , MathLib : : bigint n )
2010-04-21 18:33:21 +02:00
{
_element_size = size1 ;
_num . push_back ( n ) ;
_varid = id ;
_varname = name ;
2010-04-24 21:48:58 +02:00
}
2010-11-21 11:48:27 +01:00
CheckBufferOverrun : : ArrayInfo CheckBufferOverrun : : ArrayInfo : : limit ( MathLib : : bigint value ) const
2010-04-24 21:48:58 +02:00
{
2010-12-31 09:30:56 +01:00
MathLib : : bigint uvalue = std : : max ( MathLib : : bigint ( 0 ) , value ) ;
MathLib : : bigint n = 1 ;
2011-06-23 02:35:58 +02:00
for ( unsigned int i = 0 ; i < _num . size ( ) ; + + i )
n * = _num [ i ] ;
2010-08-06 22:37:48 +02:00
if ( uvalue > n )
n = uvalue ;
2011-06-23 02:35:58 +02:00
return ArrayInfo ( _varid , _varname , _element_size , n - uvalue ) ;
2010-04-21 18:33:21 +02:00
}
2010-04-18 19:46:45 +02:00
bool CheckBufferOverrun : : ArrayInfo : : declare ( const Token * tok , const Tokenizer & tokenizer )
2010-04-18 11:08:29 +02:00
{
_num . clear ( ) ;
2010-04-18 20:18:25 +02:00
_element_size = 0 ;
2010-04-18 19:46:45 +02:00
_varname . clear ( ) ;
2011-03-09 21:00:28 +01:00
if ( ! tok )
return false ;
2010-10-30 12:32:43 +02:00
if ( ! tok - > isName ( ) | | tok - > str ( ) = = " return " )
2010-04-18 19:46:45 +02:00
return false ;
2010-10-13 20:57:59 +02:00
while ( tok & & ( tok - > str ( ) = = " static " | |
tok - > str ( ) = = " const " | |
tok - > str ( ) = = " extern " ) )
2010-10-11 20:52:14 +02:00
tok = tok - > next ( ) ;
2011-01-06 13:02:21 +01:00
// ivar : number of type tokens
2010-04-18 19:46:45 +02:00
int ivar = 0 ;
if ( Token : : Match ( tok , " %type% *| %var% [ " ) )
ivar = 1 ;
else if ( Token : : Match ( tok , " %type% %type% *| %var% [ " ) )
ivar = 2 ;
else
return false ;
2010-10-11 20:52:14 +02:00
if ( tok - > str ( ) . find ( " : " ) ! = std : : string : : npos )
return false ;
2010-04-18 19:46:45 +02:00
// Goto variable name token, get element size..
const Token * vartok = tok - > tokAt ( ivar ) ;
if ( vartok - > str ( ) = = " * " )
{
2010-04-18 20:18:25 +02:00
_element_size = tokenizer . sizeOfType ( vartok ) ;
2010-04-18 19:46:45 +02:00
vartok = vartok - > next ( ) ;
}
2010-10-12 19:35:20 +02:00
else if ( tok - > str ( ) = = " struct " )
{
_element_size = 100 ;
}
2010-04-18 19:46:45 +02:00
else
{
2010-04-18 20:18:25 +02:00
_element_size = tokenizer . sizeOfType ( tok ) ;
2010-04-18 19:46:45 +02:00
}
_varname = vartok - > str ( ) ;
_varid = vartok - > varId ( ) ;
2011-06-23 02:35:58 +02:00
if ( ! _varid )
2010-04-26 18:52:40 +02:00
return false ;
2010-04-18 19:46:45 +02:00
const Token * atok = vartok - > tokAt ( 2 ) ;
2010-04-18 11:08:29 +02:00
2010-04-21 18:33:21 +02:00
if ( ! Token : : Match ( atok , " %num% ] ;|=|[ " ) )
2010-04-18 11:08:29 +02:00
return false ;
2010-04-21 18:33:21 +02:00
while ( Token : : Match ( atok , " %num% ] ;|=|[ " ) )
2010-04-18 11:08:29 +02:00
{
2010-12-31 09:30:56 +01:00
_num . push_back ( MathLib : : toLongNumber ( atok - > str ( ) ) ) ;
2010-04-18 11:08:29 +02:00
atok = atok - > next ( ) ;
if ( Token : : simpleMatch ( atok , " ] [ " ) )
atok = atok - > tokAt ( 2 ) ;
}
2011-03-13 17:52:45 +01:00
if ( Token : : Match ( atok , " ] = !!{ " ) )
return false ;
2010-04-21 18:33:21 +02:00
return ( ! _num . empty ( ) & & Token : : Match ( atok , " ] ;|= " ) ) ;
2010-04-18 11:08:29 +02:00
}
2010-04-10 21:12:00 +02:00
/**
* @ brief % Check for buffer overruns ( using ExecutionPath )
*/
class ExecutionPathBufferOverrun : public ExecutionPath
{
public :
/** Startup constructor */
2010-04-18 11:08:29 +02:00
ExecutionPathBufferOverrun ( Check * c , const std : : map < unsigned int , CheckBufferOverrun : : ArrayInfo > & arrayinfo )
2010-08-10 07:26:59 +02:00
: ExecutionPath ( c , 0 ) , arrayInfo ( arrayinfo ) , value ( 0 )
2010-04-10 21:12:00 +02:00
{
}
private :
2010-06-14 07:54:41 +02:00
/** @brief Copy this check. Called from the ExecutionPath baseclass. */
2010-04-10 21:12:00 +02:00
ExecutionPath * copy ( )
{
return new ExecutionPathBufferOverrun ( * this ) ;
}
2010-06-14 07:54:41 +02:00
/** @brief is other execution path equal? */
2010-04-25 11:55:57 +02:00
bool is_equal ( const ExecutionPath * e ) const
{
const ExecutionPathBufferOverrun * c = static_cast < const ExecutionPathBufferOverrun * > ( e ) ;
return ( value = = c - > value ) ;
}
2010-06-14 07:54:41 +02:00
/** @brief Buffer information */
2010-04-18 11:08:29 +02:00
const std : : map < unsigned int , CheckBufferOverrun : : ArrayInfo > & arrayInfo ;
2010-04-10 21:12:00 +02:00
/** no implementation => compiler error if used by accident */
void operator = ( const ExecutionPathBufferOverrun & ) ;
/** internal constructor for creating extra checks */
2010-04-18 11:08:29 +02:00
ExecutionPathBufferOverrun ( Check * c , const std : : map < unsigned int , CheckBufferOverrun : : ArrayInfo > & arrayinfo , unsigned int varid_ )
2010-04-15 20:08:51 +02:00
: ExecutionPath ( c , varid_ ) ,
arrayInfo ( arrayinfo )
2010-04-10 21:12:00 +02:00
{
// Pretend that variables are initialized to 0
// This checking is not about uninitialized variables
value = 0 ;
}
2010-06-14 07:54:41 +02:00
/** @brief Variable value. */
2010-12-31 09:30:56 +01:00
MathLib : : bigint value ;
2010-04-10 21:12:00 +02:00
2010-06-14 07:54:41 +02:00
/**
* @ brief Assign value to a variable
* @ param checks the execution paths
* @ param varid the variable id
* @ param value the assigned value
*/
2010-04-10 21:12:00 +02:00
static void assign_value ( std : : list < ExecutionPath * > & checks , unsigned int varid , const std : : string & value )
{
if ( varid = = 0 )
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
ExecutionPathBufferOverrun * c = dynamic_cast < ExecutionPathBufferOverrun * > ( * it ) ;
if ( c & & c - > varId = = varid )
2010-12-31 09:30:56 +01:00
c - > value = MathLib : : toLongNumber ( value ) ;
2010-04-10 21:12:00 +02:00
}
}
2010-06-14 07:54:41 +02:00
/**
* @ brief Found array usage , analyse the array usage
* @ param tok token where usage occurs ( only used when reporting the error )
* @ param checks The execution paths
* @ param varid1 variable id for the array
* @ param varid2 variable id for the index
*/
2010-04-10 21:12:00 +02:00
static void array_index ( const Token * tok , std : : list < ExecutionPath * > & checks , unsigned int varid1 , unsigned int varid2 )
{
2010-04-10 21:28:49 +02:00
if ( checks . empty ( ) | | varid1 = = 0 | | varid2 = = 0 )
2010-04-10 21:12:00 +02:00
return ;
// Locate array info corresponding to varid1
2010-04-18 11:08:29 +02:00
CheckBufferOverrun : : ArrayInfo ai ;
2010-04-10 21:12:00 +02:00
{
ExecutionPathBufferOverrun * c = dynamic_cast < ExecutionPathBufferOverrun * > ( checks . front ( ) ) ;
2010-04-18 11:08:29 +02:00
std : : map < unsigned int , CheckBufferOverrun : : ArrayInfo > : : const_iterator it ;
2010-04-10 21:12:00 +02:00
it = c - > arrayInfo . find ( varid1 ) ;
if ( it = = c - > arrayInfo . end ( ) )
return ;
ai = it - > second ;
}
// Check if varid2 variable has a value that is out-of-bounds
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
ExecutionPathBufferOverrun * c = dynamic_cast < ExecutionPathBufferOverrun * > ( * it ) ;
2011-06-23 02:35:58 +02:00
if ( c & & c - > varId = = varid2 & & c - > value > = ai . num ( 0 ) )
2010-04-10 21:12:00 +02:00
{
// variable value is out of bounds, report error
CheckBufferOverrun * checkBufferOverrun = dynamic_cast < CheckBufferOverrun * > ( c - > owner ) ;
if ( checkBufferOverrun )
{
2010-12-31 09:30:56 +01:00
std : : vector < MathLib : : bigint > index ;
2010-04-23 16:26:40 +02:00
index . push_back ( c - > value ) ;
checkBufferOverrun - > arrayIndexOutOfBounds ( tok , ai , index ) ;
2010-04-10 21:12:00 +02:00
break ;
}
}
}
}
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const
{
if ( Token : : Match ( tok . previous ( ) , " [;{}] " ) )
{
// Declaring variable..
if ( Token : : Match ( & tok , " %type% %var% ; " ) & & tok . isStandardType ( ) )
{
checks . push_back ( new ExecutionPathBufferOverrun ( owner , arrayInfo , tok . next ( ) - > varId ( ) ) ) ;
return tok . tokAt ( 2 ) ;
}
// Assign variable..
if ( Token : : Match ( & tok , " %var% = %num% ; " ) )
{
assign_value ( checks , tok . varId ( ) , tok . strAt ( 2 ) ) ;
return tok . tokAt ( 3 ) ;
}
}
// Assign variable (unknown value = 0)..
if ( Token : : Match ( & tok , " %var% = " ) )
{
assign_value ( checks , tok . varId ( ) , " 0 " ) ;
return & tok ;
}
2010-07-05 22:19:27 +02:00
// Assign variable (unknown value = 0)..
if ( Token : : Match ( tok . tokAt ( - 2 ) , " (|, & %var% ,|) " ) )
{
assign_value ( checks , tok . varId ( ) , " 0 " ) ;
return & tok ;
}
2010-04-10 21:12:00 +02:00
// Array index..
if ( Token : : Match ( & tok , " %var% [ %var% ] " ) )
{
array_index ( & tok , checks , tok . varId ( ) , tok . tokAt ( 2 ) - > varId ( ) ) ;
return tok . tokAt ( 3 ) ;
}
return & tok ;
}
} ;
/// @}
void CheckBufferOverrun : : executionPaths ( )
{
2011-06-23 04:44:11 +02:00
// Parse all variables and extract array info..
2010-04-10 21:12:00 +02:00
std : : map < unsigned int , ArrayInfo > arrayInfo ;
2011-06-24 04:31:16 +02:00
for ( size_t i = 1 ; i < = _tokenizer - > varIdCount ( ) ; i + + )
2010-04-10 21:12:00 +02:00
{
2011-06-23 04:44:11 +02:00
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( i ) ;
2011-07-20 07:57:42 +02:00
if ( var & & var - > isArray ( ) & & var - > dimension ( 0 ) > 0 )
2011-06-23 04:44:11 +02:00
arrayInfo [ i ] = ArrayInfo ( var , _tokenizer ) ;
2010-04-10 21:12:00 +02:00
}
// Perform checking - check how the arrayInfo arrays are used
ExecutionPathBufferOverrun c ( this , arrayInfo ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
}
2011-08-04 11:15:14 +02:00
void CheckBufferOverrun : : arrayIndexThenCheck ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-08-04 11:15:14 +02:00
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " %var% [ %var% ] " ) )
{
const std : : string arrayName ( tok - > str ( ) ) ;
const std : : string indexName ( tok - > strAt ( 2 ) ) ;
// skip array index..
tok = tok - > tokAt ( 4 ) ;
2011-08-10 01:45:18 +02:00
while ( tok & & tok - > str ( ) = = " [ " )
2011-08-04 11:15:14 +02:00
tok = tok - > link ( ) - > next ( ) ;
2011-08-10 01:45:18 +02:00
// syntax error
if ( ! tok )
return ;
2011-08-04 11:15:14 +02:00
// skip comparison
if ( Token : : Match ( tok , " ==|!=|<|<=|>|>= %any% && " ) )
tok = tok - > tokAt ( 2 ) ;
// check if array index is ok
if ( Token : : Match ( tok , ( " && " + indexName + " <|<= " ) . c_str ( ) ) )
arrayIndexThenCheckError ( tok , indexName ) ;
}
}
}
void CheckBufferOverrun : : arrayIndexThenCheckError ( const Token * tok , const std : : string & indexName )
{
2011-08-05 09:10:07 +02:00
reportError ( tok , Severity : : style , " arrayIndexThenCheck " ,
" Array index " + indexName + " is used before limits check \n "
" Defensive programming: The variable " + indexName + " is used as array index and then there is a check that it is within limits. This can "
" mean that the array might be accessed out-of-bounds. Reorder conditions such as '(a[i] && i < 10)' to '(i < 10 && a[i])'. That way the "
" array will not be accessed when the index is out of limits. " ) ;
2011-08-04 11:15:14 +02:00
}