2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2010-04-13 21:23:17 +02:00
* Copyright ( C ) 2007 - 2010 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>
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
2009-12-25 15:25:58 +01:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const Token * tok , int size , int index )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( size , index ) ;
2009-08-04 21:36:55 +02:00
else
{
_callStack . push_back ( tok ) ;
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( size , index ) ;
2009-08-04 21:36:55 +02:00
_callStack . pop_back ( ) ;
}
2009-01-31 20:29:27 +01:00
}
2009-03-21 21:33:27 +01:00
2009-12-25 15:25:58 +01:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( int size , int index )
2009-03-21 21:33:27 +01:00
{
2009-10-13 21:39:51 +02:00
Severity : : e severity ;
2010-04-02 07:30:58 +02:00
if ( size < = 1 | | _callStack . size ( ) > 1 )
2009-10-13 21:39:51 +02:00
{
severity = Severity : : possibleError ;
2010-04-10 14:05:33 +02:00
if ( _settings - > inconclusive = = false )
2009-10-13 21:39:51 +02:00
return ;
}
else
{
severity = Severity : : error ;
}
2010-04-02 07:30:58 +02:00
if ( _callStack . size ( ) = = 1 )
2009-12-25 15:25:58 +01:00
{
std : : ostringstream oss ;
oss < < " Array ' " < < ( * _callStack . begin ( ) ) - > str ( ) < < " [ " < < size < < " ]' index " < < index < < " out of bounds " ;
reportError ( _callStack , severity , " arrayIndexOutOfBounds " , oss . str ( ) . c_str ( ) ) ;
}
else
reportError ( _callStack , severity , " arrayIndexOutOfBounds " , " Array index out of bounds " ) ;
2009-03-21 21:33:27 +01:00
}
2010-04-23 16:26:40 +02:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const Token * tok , const ArrayInfo & arrayInfo , const std : : vector < int > & index )
2010-04-18 11:08:29 +02:00
{
std : : ostringstream oss ;
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
{
oss < < arrayInfo . varname ;
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-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
{
2009-10-13 23:09:37 +02:00
Severity : : e severity ;
2010-04-02 07:30:58 +02:00
if ( _callStack . size ( ) > 0 )
2009-10-13 23:09:37 +02:00
{
severity = Severity : : possibleError ;
2010-04-10 14:05:33 +02:00
if ( _settings - > inconclusive = = false )
2009-10-13 23:09:37 +02:00
return ;
}
else
{
severity = Severity : : error ;
}
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 ;
reportError ( tok , severity , " bufferAccessOutOfBounds " , errmsg ) ;
2009-03-21 21:33:27 +01:00
}
2009-10-01 09:59:27 +02:00
void CheckBufferOverrun : : dangerousStdCin ( const Token * tok )
{
2010-04-10 14:05:33 +02:00
if ( _settings & & _settings - > inconclusive = = false )
2009-10-13 22:33:41 +02:00
return ;
2009-10-01 09:59:27 +02:00
reportError ( tok , Severity : : possibleError , " dangerousStdCin " , " Dangerous usage of std::cin, possible buffer overrun " ) ;
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : strncatUsage ( const Token * tok )
2009-03-21 21:33:27 +01:00
{
2010-04-10 14:05:33 +02:00
if ( _settings & & _settings - > inconclusive = = false )
2009-10-13 22:33:41 +02:00
return ;
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
{
2010-04-10 14:05:33 +02:00
if ( _settings & & _settings - > inconclusive = = false )
2009-10-13 22:33:41 +02:00
return ;
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-12-18 17:26:15 +01:00
void CheckBufferOverrun : : terminateStrncpyError ( const Token * tok )
{
reportError ( tok , Severity : : style , " terminateStrncpy " , " After a strncpy() the buffer should be zero-terminated " ) ;
}
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-04-21 18:33:21 +02:00
/**
* Parse for loop initialization statement . Look for a counter variable
* \ param tok [ in ] first token inside the paranthesis
* \ 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 )
{
if ( Token : : Match ( tok2 , " %varid% < %num% ; " , varid ) )
{
maxMinFlipped = false ;
long value = MathLib : : toLongNumber ( tok2 - > strAt ( 2 ) ) ;
max_value = MathLib : : toString < long > ( value - 1 ) ;
}
else if ( Token : : Match ( tok2 , " %varid% <= %num% ; " , varid ) )
{
maxMinFlipped = false ;
max_value = tok2 - > strAt ( 2 ) ;
}
else if ( Token : : Match ( tok2 , " %num% < %varid% ; " , varid ) )
{
maxMinFlipped = true ;
long value = MathLib : : toLongNumber ( tok2 - > str ( ) ) ;
max_value = min_value ;
min_value = MathLib : : toString < long > ( value + 1 ) ;
}
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 ;
}
/**
* Parse the third substatement in for head
* \ 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 ) )
{
if ( ! MathLib : : isInt ( tok - > strAt ( 2 ) ) )
return false ;
const int num = MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) ;
// 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
long max = MathLib : : toLongNumber ( max_value ) ;
long min = MathLib : : toLongNumber ( min_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_value = MathLib : : toString < long > ( max ) ;
}
else if ( Token : : Match ( tok , " %varid% = %varid% + %num% ) " , varid ) )
{
if ( ! MathLib : : isInt ( tok - > strAt ( 4 ) ) )
return false ;
const int num = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
long max = MathLib : : toLongNumber ( max_value ) ;
long min = MathLib : : toLongNumber ( min_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_value = MathLib : : toString < long > ( max ) ;
}
else if ( Token : : Match ( tok , " %varid% -= %num% ) " , varid ) | |
Token : : Match ( tok , " %varid% = %num% - %varid% ) " , varid ) )
{
if ( ! MathLib : : isInt ( tok - > strAt ( 2 ) ) )
return false ;
const int num = MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) ;
long max = MathLib : : toLongNumber ( max_value ) ;
long min = MathLib : : toLongNumber ( min_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_value = MathLib : : toString < long > ( max ) ;
}
else if ( Token : : Match ( tok , " %varid% = %varid% - %num% ) " , varid ) )
{
if ( ! MathLib : : isInt ( tok - > strAt ( 4 ) ) )
return false ;
const int num = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
long max = MathLib : : toLongNumber ( max_value ) ;
long min = MathLib : : toLongNumber ( min_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_value = MathLib : : toString < long > ( max ) ;
}
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
* \ param tok first token of for - body
* \ 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 )
{
2010-04-22 19:22:23 +02:00
const std : : string pattern ( ( arrayInfo . varid ? std : : string ( " %varid% " ) : arrayInfo . varname ) + " [ " + strindex + " ] " ) ;
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 ;
}
if ( Token : : Match ( tok2 , " if|switch " ) )
{
// Bailout
break ;
}
if ( condition_out_of_bounds & & Token : : Match ( tok2 , pattern . c_str ( ) , arrayInfo . varid ) )
{
bufferOverrun ( tok2 , arrayInfo . varname ) ;
break ;
}
2010-04-22 19:22:23 +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
{
int min_index = 0 ;
int max_index = 0 ;
if ( Token : : Match ( tok2 , " %varid% [ %var% +|-|*|/ %num% ] " , arrayInfo . varid ) & &
tok2 - > tokAt ( 2 ) - > varId ( ) = = counter_varid )
{
const char action = tok2 - > strAt ( 3 ) [ 0 ] ;
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());
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 ( ) ) ;
}
else if ( Token : : Match ( tok2 , " %varid% [ %num% +|-|*|/ %var% ] " , arrayInfo . varid ) & &
tok2 - > tokAt ( 4 ) - > varId ( ) = = counter_varid )
{
const char action = tok2 - > strAt ( 3 ) [ 0 ] ;
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());
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 ( ) ) ;
}
//printf("min_index = %d, max_index = %d, size = %d\n", min_index, max_index, size);
if ( min_index > = ( int ) arrayInfo . num [ 0 ] | | max_index > = ( int ) arrayInfo . num [ 0 ] )
{
arrayIndexOutOfBounds ( tok2 , ( int ) arrayInfo . num [ 0 ] , std : : max ( min_index , max_index ) ) ;
}
}
}
}
2010-04-21 20:02:58 +02:00
void CheckBufferOverrun : : checkFunctionCall ( const Token & tok , unsigned int par , const ArrayInfo & arrayInfo )
2010-04-21 19:27:28 +02:00
{
std : : map < std : : string , unsigned int > total_size ;
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-04-21 21:08:47 +02:00
total_size [ " write " ] = 3 ;
}
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 ( ) )
{
unsigned int arg = it - > second ;
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% ,|) " ) )
{
const long sz = MathLib : : toLongNumber ( tok2 - > strAt ( 1 ) ) ;
unsigned int elements = 1 ;
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 20:02: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% ,|) " ) )
{
const long sz = MathLib : : toLongNumber ( tok2 - > strAt ( 1 ) ) * MathLib : : toLongNumber ( tok2 - > strAt ( 3 ) ) ;
unsigned int elements = 1 ;
for ( unsigned int i = 0 ; i < arrayInfo . num . size ( ) ; + + i )
elements * = arrayInfo . num [ i ] ;
if ( sz < 0 | | sz > int ( elements * arrayInfo . element_size ) )
{
bufferOverrun ( & tok , arrayInfo . varname ) ;
}
}
break ;
}
2010-04-21 19:27:28 +02:00
}
}
}
}
2010-04-21 18:33:21 +02:00
2010-02-14 19:58:17 +01:00
void CheckBufferOverrun : : checkScope ( const Token * tok , const std : : vector < std : : string > & varname , const int size , const int 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-03-09 12:04:22 +01:00
const unsigned int varc ( varname . empty ( ) ? 0 : ( varname . size ( ) - 1 ) * 2 ) ;
2010-03-09 12:41:40 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( 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-02-14 19:58:17 +01:00
int 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-02-14 19:58:17 +01:00
int 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
}
}
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 ;
}
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-02-14 19:58:17 +01:00
int 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
{
2010-04-02 07:30:58 +02:00
if ( index > size | | ! Token : : Match ( 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-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-02-14 19:58:17 +01:00
int 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-04-21 20:02:58 +02:00
if ( varid = = 0 )
2009-01-31 20:29:27 +01:00
{
2010-04-21 19:27:28 +02:00
ArrayInfo arrayInfo ( 0 , varnames , 1 , total_size ) ;
2010-04-21 20:02:58 +02:00
if ( Token : : Match ( tok , ( " %var% ( " + varnames + " , " ) . c_str ( ) ) )
checkFunctionCall ( * tok , 1 , arrayInfo ) ;
if ( Token : : Match ( tok , ( " %var% ( %var% , " + varnames + " , " ) . c_str ( ) ) )
checkFunctionCall ( * 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
{
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 ;
2010-04-21 18:33:21 +02:00
tok2 = for_init ( tok2 , counter_varid , min_counter_value ) ;
if ( tok2 = = 0 | | counter_varid = = 0 )
2009-10-03 16:27:16 +02:00
continue ;
2010-04-12 21:04:59 +02:00
bool maxMinFlipped = false ;
2010-04-21 18:33:21 +02:00
std : : string strindex ;
if ( ! for_condition ( tok2 , counter_varid , min_counter_value , max_counter_value , strindex , maxMinFlipped ) )
2010-02-15 22:20:09 +01:00
continue ;
2009-01-31 20:29:27 +01:00
// Get index variable and stopsize.
2009-08-02 15:34:28 +02:00
bool condition_out_of_bounds = true ;
2010-04-12 21:04:59 +02:00
if ( MathLib : : toLongNumber ( max_counter_value ) < size )
2009-09-27 17:11:57 +02:00
condition_out_of_bounds = false ;
2009-01-31 20:29:27 +01:00
2010-04-21 18:33:21 +02:00
if ( ! for3 ( tok2 - > tokAt ( 4 ) , counter_varid , min_counter_value , max_counter_value , maxMinFlipped ) )
2009-09-27 17:07:54 +02:00
continue ;
2010-04-21 18:33:21 +02:00
if ( Token : : Match ( tok2 - > tokAt ( 4 ) , " %var% =|+=|-= " ) & & MathLib : : toLongNumber ( max_counter_value ) < = size )
condition_out_of_bounds = false ;
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 ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 | | ! tok2 - > tokAt ( 5 ) )
2009-01-31 20:29:27 +01:00
break ;
2009-10-01 10:33:53 +02:00
// Check is the counter variable increased elsewhere inside the loop or used
// for anything else except reading
2010-04-21 18:33:21 +02:00
if ( for_bailout ( tok2 - > next ( ) , counter_varid ) )
2009-10-01 10:33:53 +02:00
break ;
2009-08-02 14:26:26 +02:00
2010-04-21 18:33:21 +02:00
ArrayInfo arrayInfo ( varid , varnames , size , total_size ) ;
parse_for_body ( tok2 - > next ( ) , arrayInfo , strindex , condition_out_of_bounds , counter_varid , min_counter_value , max_counter_value ) ;
2009-08-02 14:26:26 +02:00
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-04-21 18:33:21 +02:00
const long len = Token : : getStrLength ( tok - > tokAt ( varc + 4 ) ) ;
2010-04-02 07:30:58 +02:00
if ( len < 0 | | len > = 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
}
}
2009-02-20 22:16:07 +01:00
2009-08-30 13:44:23 +02:00
// Detect few strcat() calls
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " strcat ( %varid% , %str% ) ; " , varid ) )
2009-08-30 13:44:23 +02:00
{
size_t charactersAppend = 0 ;
const Token * tok2 = tok ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & Token : : Match ( tok2 , " strcat ( %varid% , %str% ) ; " , varid ) )
2009-08-30 13:44:23 +02:00
{
charactersAppend + = Token : : getStrLength ( tok2 - > tokAt ( 4 ) ) ;
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 ;
}
tok2 = tok2 - > tokAt ( 7 ) ;
}
}
2009-01-31 20:29:27 +01:00
2010-04-21 18:33:21 +02:00
// sprintf / snprintf..
if ( varid > 0 )
2009-01-31 20:29:27 +01:00
{
2010-04-21 18:33:21 +02:00
if ( Token : : Match ( tok , " sprintf ( %varid% , %str% [,)] " , varid ) )
{
checkSprintfCall ( tok , total_size ) ;
}
2009-01-31 20:29:27 +01:00
2010-04-21 18:33:21 +02:00
// snprintf..
if ( Token : : Match ( tok , " snprintf ( %varid% , %num% , " , varid ) )
{
int n = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
if ( n > total_size )
outOfBounds ( tok - > tokAt ( 4 ) , " snprintf size " ) ;
}
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.
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% ( " ) )
2009-01-31 20:29:27 +01:00
{
// Only perform this checking if showAll setting is enabled..
2010-04-10 14:05:33 +02:00
if ( ! _settings - > inconclusive )
2009-01-31 20:29:27 +01:00
continue ;
unsigned int parlevel = 0 , par = 0 ;
2009-12-25 15:25:58 +01:00
const Token * tok1 = tok ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-01-31 20:29:27 +01:00
{
+ + parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-01-31 20:29:27 +01:00
{
- - parlevel ;
2010-04-02 07:30:58 +02:00
if ( parlevel < 1 )
2009-01-31 20:29:27 +01:00
{
par = 0 ;
break ;
}
}
2010-04-02 07:30:58 +02:00
else if ( parlevel = = 1 & & ( tok2 - > str ( ) = = " , " ) )
2009-01-31 20:29:27 +01:00
{
+ + par ;
}
2010-04-02 07:30:58 +02:00
if ( parlevel = = 1 )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok2 , " [(,] %varid% [,)] " , varid ) )
2009-10-28 21:42:54 +01:00
{
+ + par ;
2009-12-25 15:25:58 +01:00
tok1 = tok2 - > next ( ) ;
break ;
}
2010-04-02 07:30:58 +02:00
else if ( varid = = 0 & & Token : : Match ( tok2 , ( " [(,] " + varnames + " [,)] " ) . c_str ( ) ) )
2009-12-25 15:25:58 +01:00
{
+ + par ;
tok1 = tok2 - > tokAt ( varc + 1 ) ;
2009-10-28 21:42:54 +01:00
break ;
}
2009-01-31 20:29:27 +01:00
}
}
2010-04-02 07:30:58 +02:00
if ( par = = 0 )
2009-01-31 20:29:27 +01:00
continue ;
// Find function..
2009-07-05 22:16:43 +02:00
const Token * ftok = _tokenizer - > getFunctionTokenByName ( tok - > str ( ) . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! ftok )
2009-01-31 20:29:27 +01:00
continue ;
// Parse head of function..
ftok = ftok - > tokAt ( 2 ) ;
parlevel = 1 ;
2010-04-02 07:30:58 +02:00
while ( ftok & & parlevel = = 1 & & par > = 1 )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ftok - > str ( ) = = " ( " )
2009-01-31 20:29:27 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( ftok - > str ( ) = = " ) " )
2009-01-31 20:29:27 +01:00
- - parlevel ;
2010-04-02 07:30:58 +02:00
else if ( ftok - > str ( ) = = " , " )
2009-01-31 20:29:27 +01:00
- - par ;
2010-04-02 07:30:58 +02:00
else if ( par = = 1 & & parlevel = = 1 & & Token : : Match ( ftok , " %var% [,)] " ) )
2009-01-31 20:29:27 +01:00
{
// Parameter name..
2010-02-14 19:58:17 +01:00
std : : vector < std : : string > parname ;
parname . push_back ( ftok - > str ( ) ) ;
const unsigned int parId = ftok - > varId ( ) ;
2009-01-31 20:29:27 +01:00
// Goto function body..
2010-04-02 07:30:58 +02:00
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
2009-01-31 20:29:27 +01:00
ftok = ftok - > next ( ) ;
ftok = ftok ? ftok - > next ( ) : 0 ;
2009-12-25 15:25:58 +01:00
// Don't make recursive checking..
2010-04-02 07:30:58 +02:00
if ( std : : find_if ( _callStack . begin ( ) , _callStack . end ( ) , TokenStrEquals ( tok1 - > str ( ) ) ) ! = _callStack . end ( ) )
2009-12-25 15:25:58 +01:00
continue ;
2009-01-31 20:29:27 +01:00
// Check variable usage in the function..
2009-12-25 15:25:58 +01:00
_callStack . push_back ( tok1 ) ;
2010-02-14 19:58:17 +01:00
checkScope ( ftok , parname , size , total_size , parId ) ;
2009-01-31 20:29:27 +01:00
_callStack . pop_back ( ) ;
// break out..
break ;
}
ftok = ftok - > next ( ) ;
}
}
}
}
2010-04-21 18:33:21 +02:00
void CheckBufferOverrun : : checkScope ( const Token * tok , const ArrayInfo & arrayInfo )
{
const unsigned int total_size = arrayInfo . num [ 0 ] * arrayInfo . element_size ;
unsigned int indentlevel = 0 ;
for ( ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
if ( indentlevel = = 0 )
return ;
- - indentlevel ;
}
else if ( Token : : Match ( tok , " %varid% [ %num% ] " , arrayInfo . varid ) )
{
2010-04-23 16:26:40 +02:00
std : : vector < int > indexes ;
for ( const Token * tok2 = tok - > next ( ) ; Token : : Match ( tok2 , " [ %num% ] " ) ; tok2 = tok2 - > tokAt ( 3 ) )
2010-04-21 18:33:21 +02:00
{
2010-04-23 16:26:40 +02:00
const int index = MathLib : : toLongNumber ( tok2 - > strAt ( 1 ) ) ;
if ( index < 0 )
{
indexes . clear ( ) ;
break ;
}
indexes . push_back ( index ) ;
}
if ( indexes . size ( ) = = arrayInfo . num . size ( ) )
{
// 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..
unsigned int totalElements = 1 ;
// total index..
unsigned int totalIndex = 0 ;
// calculate the totalElements and totalIndex..
for ( unsigned int i = 0 ; i < indexes . size ( ) ; + + i )
{
unsigned int ri = indexes . size ( ) - 1 - i ;
totalIndex + = indexes [ ri ] * totalElements ;
totalElements * = arrayInfo . num [ ri ] ;
}
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
}
// cin..
else if ( Token : : Match ( tok , " cin >> %varid% ; " , arrayInfo . varid ) )
{
dangerousStdCin ( tok ) ;
}
// Loop..
else if ( Token : : simpleMatch ( tok , " for ( " ) )
{
const Token * tok2 = tok - > tokAt ( 2 ) ;
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 )
continue ;
bool maxMinFlipped = false ;
std : : string strindex ;
if ( ! for_condition ( tok2 , counter_varid , min_counter_value , max_counter_value , strindex , maxMinFlipped ) )
continue ;
// Get index variable and stopsize.
bool condition_out_of_bounds = true ;
if ( MathLib : : toLongNumber ( max_counter_value ) < ( int ) arrayInfo . num [ 0 ] )
condition_out_of_bounds = false ;
if ( ! for3 ( tok2 - > tokAt ( 4 ) , counter_varid , min_counter_value , max_counter_value , maxMinFlipped ) )
continue ;
if ( Token : : Match ( tok2 - > tokAt ( 4 ) , " %var% =|+=|-= " ) & & MathLib : : toLongNumber ( max_counter_value ) < = ( int ) arrayInfo . num [ 0 ] )
condition_out_of_bounds = false ;
// Goto the end paranthesis of the for-statement: "for (x; y; z)" ..
tok2 = tok - > next ( ) - > link ( ) ;
if ( ! tok2 | | ! tok2 - > tokAt ( 5 ) )
break ;
// Check is the counter variable increased elsewhere inside the loop or used
// for anything else except reading
if ( for_bailout ( tok2 - > next ( ) , counter_varid ) )
break ;
parse_for_body ( tok2 - > next ( ) , arrayInfo , strindex , condition_out_of_bounds , counter_varid , min_counter_value , max_counter_value ) ;
continue ;
}
2010-04-21 19:27:28 +02:00
// Check function call..
2010-04-21 20:02:58 +02:00
if ( Token : : Match ( tok , " %var% ( %varid% , " , arrayInfo . varid ) )
checkFunctionCall ( * tok , 1 , arrayInfo ) ;
if ( Token : : Match ( tok , " %var% ( %var% , %varid% , " , arrayInfo . varid ) )
checkFunctionCall ( * tok , 2 , arrayInfo ) ;
2010-04-21 18:33:21 +02:00
2010-04-21 19:27:28 +02:00
2010-04-22 20:07:41 +02:00
if ( _settings - > _checkCodingStyle )
{
// check for strncpy which is not terminated
if ( Token : : Match ( tok , " strncpy ( %varid% , %any% , %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
{
2010-04-22 20:07:41 +02: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..
if ( Token : : Match ( tok , " strncpy|strncat ( %varid% , %any% , %num% ) " , arrayInfo . varid ) )
{
if ( tok - > str ( ) = = " strncat " )
{
const unsigned int n = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) ;
if ( n > = total_size )
strncatUsage ( tok ) ;
}
// Dangerous usage of strncpy + strncat..
if ( Token : : Match ( tok - > tokAt ( 8 ) , " ; strncat ( %varid% , %any% , %num% ) " , arrayInfo . varid ) )
{
const unsigned int n = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) + MathLib : : toLongNumber ( tok - > strAt ( 15 ) ) ;
if ( n > total_size )
strncatUsage ( tok - > tokAt ( 9 ) ) ;
}
}
// Writing data into array..
if ( Token : : Match ( tok , " strcpy|strcat ( %varid% , %str% ) " , arrayInfo . varid ) )
{
const unsigned long len = Token : : getStrLength ( tok - > tokAt ( 4 ) ) ;
if ( len > = total_size )
{
bufferOverrun ( tok , arrayInfo . varname ) ;
continue ;
}
}
// Detect few strcat() calls
if ( Token : : Match ( tok , " strcat ( %varid% , %str% ) ; " , arrayInfo . varid ) )
{
size_t charactersAppend = 0 ;
const Token * tok2 = tok ;
while ( tok2 & & Token : : Match ( tok2 , " strcat ( %varid% , %str% ) ; " , arrayInfo . varid ) )
{
charactersAppend + = Token : : getStrLength ( tok2 - > tokAt ( 4 ) ) ;
if ( charactersAppend > = static_cast < size_t > ( total_size ) )
{
bufferOverrun ( tok2 , arrayInfo . varname ) ;
break ;
}
tok2 = tok2 - > tokAt ( 7 ) ;
}
}
if ( Token : : Match ( tok , " sprintf ( %varid% , %str% [,)] " , arrayInfo . varid ) )
{
checkSprintfCall ( tok , total_size ) ;
}
// snprintf..
if ( Token : : Match ( tok , " snprintf ( %varid% , %num% , " , arrayInfo . varid ) )
{
const unsigned int n = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
if ( n > total_size )
outOfBounds ( tok - > tokAt ( 4 ) , " snprintf size " ) ;
}
}
}
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
{
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 ;
2010-03-30 17:33:17 +02:00
int size = 0 ;
2010-02-14 19:58:17 +01:00
std : : string type ;
2009-02-11 17:12:29 +01:00
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 "[;{}]"
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-04-21 18:33:21 +02:00
ArrayInfo arrayInfo ;
if ( arrayInfo . declare ( tok , * _tokenizer ) )
2009-02-11 17:12:29 +01:00
{
2010-04-21 18:33:21 +02:00
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
checkScope ( tok , arrayInfo ) ;
continue ;
2009-02-11 17:12:29 +01:00
}
2010-04-21 18:33:21 +02:00
if ( Token : : Match ( tok , " %type% *| %var% [ %var% ] [;=] " ) )
2010-03-28 15:56:13 +02:00
{
unsigned int varpos = 1 ;
2010-04-02 07:30:58 +02:00
if ( tok - > next ( ) - > str ( ) = = " * " )
2010-03-28 15:56:13 +02:00
+ + varpos ;
2010-03-29 17:25:38 +02:00
// make sure the variable is defined
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( varpos + 2 ) - > varId ( ) = = 0 )
2010-03-29 17:25:38 +02:00
continue ; // FIXME we loose the check for negative index when we bail
2010-03-28 15:56:13 +02:00
// get maximum size from type
// find where this token is defined
const Token * index_type = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , tok - > tokAt ( varpos + 2 ) - > varId ( ) ) ;
index_type = index_type - > previous ( ) ;
2010-04-02 07:30:58 +02:00
if ( index_type - > str ( ) = = " char " )
2010-03-28 15:56:13 +02:00
{
2010-04-02 07:30:58 +02:00
if ( index_type - > isUnsigned ( ) )
2010-03-28 15:56:13 +02:00
size = UCHAR_MAX + 1 ;
2010-04-02 07:30:58 +02:00
else if ( index_type - > isSigned ( ) )
2010-03-28 15:56:13 +02:00
size = SCHAR_MAX + 1 ;
else
size = CHAR_MAX + 1 ;
}
2010-04-02 07:30:58 +02:00
else if ( index_type - > str ( ) = = " short " )
2010-03-28 15:56:13 +02:00
{
2010-04-02 07:30:58 +02:00
if ( index_type - > isUnsigned ( ) )
2010-03-28 15:56:13 +02:00
size = USHRT_MAX + 1 ;
else
size = SHRT_MAX + 1 ;
}
2010-03-30 17:33:17 +02:00
// checkScope assumes size is signed int so we limit the following sizes to INT_MAX
2010-04-02 07:30:58 +02:00
else if ( index_type - > str ( ) = = " int " )
2010-03-28 15:56:13 +02:00
{
2010-04-02 07:30:58 +02:00
if ( index_type - > isUnsigned ( ) )
2010-03-30 17:33:17 +02:00
size = INT_MAX ; // should be UINT_MAX + 1U;
2010-03-28 15:56:13 +02:00
else
2010-03-30 17:33:17 +02:00
size = INT_MAX ; // should be INT_MAX + 1U;
2010-03-28 15:56:13 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( index_type - > str ( ) = = " long " )
2010-03-28 15:56:13 +02:00
{
2010-04-02 07:30:58 +02:00
if ( index_type - > isUnsigned ( ) )
2010-03-28 15:56:13 +02:00
{
2010-04-02 07:30:58 +02:00
if ( index_type - > isLong ( ) )
2010-03-30 17:33:17 +02:00
size = INT_MAX ; // should be ULLONG_MAX + 1ULL;
2010-03-28 15:56:13 +02:00
else
2010-03-30 17:33:17 +02:00
size = INT_MAX ; // should be ULONG_MAX + 1UL;
2010-03-28 15:56:13 +02:00
}
else
{
2010-04-02 07:30:58 +02:00
if ( index_type - > isLong ( ) )
2010-03-30 17:33:17 +02:00
size = INT_MAX ; // should be LLONG_MAX + 1LL;
2010-03-28 15:56:13 +02:00
else
2010-03-30 17:33:17 +02:00
size = INT_MAX ; // should be LONG_MAX + 1L;
2010-03-28 15:56:13 +02:00
}
}
type = tok - > strAt ( varpos - 1 ) ;
varid = tok - > tokAt ( varpos ) - > varId ( ) ;
nextTok = varpos + 5 ;
}
2010-04-02 07:30:58 +02:00
else 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-04-02 07:30:58 +02:00
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = malloc ( %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
const Token * declTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " [;{}] %type% * %varid% ; " , varid ) ;
2010-04-11 20:57:30 +02:00
if ( ! declTok )
continue ;
2010-04-10 07:57:29 +02:00
type = declTok - > next ( ) - > str ( ) ;
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
2010-04-10 07:57:29 +02:00
unsigned int sizeOfType = _tokenizer - > sizeOfType ( declTok - > next ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( sizeOfType > 0 )
2009-11-15 16:49:47 +01:00
size / = 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-03-09 11:03:45 +01:00
int total_size = size * _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
2009-02-11 17:12:29 +01:00
// The callstack is empty
_callStack . clear ( ) ;
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
{
const char declstruct [ ] = " struct|class %var% { " ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , declstruct ) ;
tok ; tok = Token : : findmatch ( tok - > next ( ) , declstruct ) )
2009-01-31 20:29:27 +01:00
{
const std : : string & structname = tok - > next ( ) - > str ( ) ;
// Found a struct declaration. Search for arrays..
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; 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..
if ( arrayInfo . num . size ( ) > 1 )
2009-01-31 20:29:27 +01:00
continue ;
2010-04-18 20:06:54 +02:00
std : : vector < std : : string > varname ;
varname . push_back ( " " ) ;
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 ;
2010-04-18 20:18:25 +02:00
checkScope ( tok4 - > tokAt ( 2 ) , v , arrayInfo . num [ 0 ] , 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..
2010-04-18 20:18:25 +02:00
checkScope ( CheckTok , varname , arrayInfo . num [ 0 ] , 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 ( ) ;
2009-01-31 20:29:27 +01:00
}
//---------------------------------------------------------------------------
2009-10-08 15:27:46 +02:00
int 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 ;
int input_string_size = 1 ;
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-03-09 11:03:45 +01:00
unsigned int 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-03-09 11:03:45 +01:00
unsigned int tempDigits = std : : abs ( std : : atoi ( digits_string . c_str ( ) ) ) ;
2010-04-02 07:30:58 +02:00
if ( i_d_x_f_found )
2009-10-18 12:58:48 +02:00
tempDigits = std : : max ( static_cast < int > ( tempDigits ) , 1 ) ;
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-03-09 11:03:45 +01:00
unsigned int maxLen = std : : max ( std : : abs ( std : : atoi ( endStr . c_str ( ) ) ) , 1 ) ;
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
}
}
2009-10-18 12:58:48 +02:00
return input_string_size ;
2009-09-25 18:23:44 +02:00
}
2009-01-31 20:29:27 +01:00
2009-10-07 14:37:20 +02:00
void CheckBufferOverrun : : checkSprintfCall ( const Token * tok , int size )
{
2009-10-11 20:36:22 +02:00
std : : list < const Token * > parameters ;
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 5 ) - > str ( ) = = " , " )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
const Token * end = tok - > next ( ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 5 ) ; 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 ( ) ) ;
// TODO, get value of the variable if possible and use that instead of 0
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 ) ;
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
int len = countSprintfLength ( tok - > tokAt ( 4 ) - > 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-04-18 20:51:39 +02:00
void CheckBufferOverrun : : negativeIndexError ( const Token * tok , long index )
{
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 ) )
{
const long index = MathLib : : toLongNumber ( tok - > next ( ) - > str ( ) ) ;
if ( index < 0 )
{
2010-04-20 16:43:51 +02:00
// Multidimension index => error
if ( Token : : simpleMatch ( tok - > previous ( ) , " ] " ) | | Token : : simpleMatch ( tok - > tokAt ( 3 ) , " [ " ) )
negativeIndexError ( tok , index ) ;
// 1-dimensional array => error
else if ( tok - > previous ( ) & & tok - > previous ( ) - > varId ( ) )
{
const Token * tok2 = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , tok - > previous ( ) - > varId ( ) ) ;
if ( tok2 & & Token : : Match ( tok2 - > next ( ) , " [ %any% ] ; " ) )
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-18 20:18:25 +02:00
: num ( _num ) , element_size ( _element_size ) , varid ( _varid ) , varname ( _varname )
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 )
2010-04-18 20:18:25 +02:00
: num ( _num ) , element_size ( _element_size ) , varid ( _varid ) , varname ( _varname )
2010-04-18 11:08:29 +02:00
{
* this = ai ;
}
const CheckBufferOverrun : : ArrayInfo & CheckBufferOverrun : : ArrayInfo : : operator = ( const CheckBufferOverrun : : ArrayInfo & ai )
{
if ( & ai ! = this )
{
2010-04-18 20:18:25 +02:00
_element_size = ai . element_size ;
2010-04-18 19:46:45 +02:00
_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 .
*/
CheckBufferOverrun : : ArrayInfo : : ArrayInfo ( unsigned int id , const std : : string & name , unsigned int size1 , unsigned int n )
: num ( _num ) , element_size ( _element_size ) , varid ( _varid ) , varname ( _varname )
{
_element_size = size1 ;
_num . push_back ( n ) ;
_varid = id ;
_varname = name ;
}
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 ( ) ;
if ( ! tok - > isName ( ) )
return false ;
int ivar = 0 ;
if ( Token : : Match ( tok , " %type% *| %var% [ " ) )
ivar = 1 ;
else if ( Token : : Match ( tok , " %type% %type% *| %var% [ " ) )
ivar = 2 ;
else
return false ;
// 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 ( ) ;
}
else
{
2010-04-18 20:18:25 +02:00
_element_size = tokenizer . sizeOfType ( tok ) ;
2010-04-18 19:46:45 +02:00
}
2010-04-18 20:18:25 +02:00
if ( _element_size = = 0 )
2010-04-18 19:46:45 +02:00
return false ;
_varname = vartok - > str ( ) ;
_varid = vartok - > varId ( ) ;
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
{
_num . push_back ( MathLib : : toLongNumber ( atok - > str ( ) ) ) ;
atok = atok - > next ( ) ;
if ( Token : : simpleMatch ( atok , " ] [ " ) )
atok = atok - > tokAt ( 2 ) ;
}
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-04-15 20:08:51 +02:00
: ExecutionPath ( c , 0 ) , arrayInfo ( arrayinfo )
2010-04-10 21:12:00 +02:00
{
}
private :
/** Copy this check */
ExecutionPath * copy ( )
{
return new ExecutionPathBufferOverrun ( * this ) ;
}
/** @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 ;
}
unsigned int value ;
/** @brief Assign value to a variable */
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 )
c - > value = MathLib : : toLongNumber ( value ) ;
}
}
/** @brief Found array usage.. */
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 ) ;
2010-04-18 11:08:29 +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-04-23 16:26:40 +02:00
std : : vector < int > index ;
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 ;
}
// 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 ( )
{
// Parse all tokens and extract array info..
std : : map < unsigned int , ArrayInfo > arrayInfo ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2010-04-18 19:46:45 +02:00
if ( Token : : Match ( tok , " [;{}] %type% " ) )
2010-04-10 21:12:00 +02:00
{
ArrayInfo ai ;
2010-04-18 19:46:45 +02:00
if ( ! ai . declare ( tok - > next ( ) , * _tokenizer ) )
2010-04-18 11:08:29 +02:00
continue ;
2010-04-18 19:46:45 +02:00
arrayInfo [ ai . varid ] = ai ;
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 ) ;
}