2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2010-02-15 22:20:09 +01:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-01-31 20:29:27 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-31 20:29:27 +01:00
*/
//---------------------------------------------------------------------------
// Buffer overrun..
//---------------------------------------------------------------------------
# include "checkbufferoverrun.h"
2009-02-11 06:16:10 +01:00
# include "tokenize.h"
# include "errorlogger.h"
2009-08-02 14:26:26 +02:00
# include "mathlib.h"
2009-02-11 06:16:10 +01:00
2009-01-31 20:29:27 +01:00
# include <algorithm>
# include <sstream>
# include <list>
# include <cstring>
2009-09-20 12:54:19 +02:00
# include <cctype>
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-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-02 07:30:58 +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 :
const std : : string value ;
} ;
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-02 07:30:58 +02:00
if ( index < 0 | | 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-02 07:30:58 +02:00
if ( index < 0 | | 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-02 07:30:58 +02:00
if ( index < 0 | | 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-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 ( _settings - > _checkCodingStyle )
2009-12-18 17:26:15 +01:00
{
// check for strncpy which is not terminated
2010-04-05 20:47:50 +02:00
if ( Token : : Match ( tok , " strncpy ( %varid% , %any% , %num% ) " , varid ) )
2009-12-18 17:26:15 +01:00
{
2010-04-05 20:47:50 +02:00
// strncpy takes entire variable length as input size
if ( MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) = = total_size )
2009-12-18 17:26:15 +01:00
{
2010-04-05 20:47:50 +02:00
const Token * tok2 = tok - > next ( ) - > link ( ) - > next ( ) ;
for ( ; tok2 ; tok2 = tok2 - > next ( ) )
2009-12-18 17:26:15 +01:00
{
2010-04-05 20:47:50 +02:00
if ( tok2 - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) )
2009-12-18 17:26:15 +01:00
{
2010-04-05 20:47:50 +02:00
if ( ! Token : : Match ( tok2 , " %varid% [ %any% ] = 0 ; " , tok - > tokAt ( 2 ) - > varId ( ) ) )
2009-12-18 17:26:15 +01:00
{
2010-04-05 20:47:50 +02:00
terminateStrncpyError ( tok ) ;
2009-12-18 17:26:15 +01:00
}
2010-04-05 20:47:50 +02:00
break ;
2009-12-18 17:26:15 +01:00
}
}
}
}
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " memset|memcpy|memmove|memcmp|strncpy|fgets ( %varid% , %any% , %any% ) " , varid ) | |
Token : : Match ( tok , " memset|memcpy|memmove|memcmp|fgets ( %var% , %varid% , %any% ) " , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
const Token * tokSz = tok - > tokAt ( 6 ) ;
2010-04-02 07:30:58 +02:00
if ( tokSz - > str ( ) [ 0 ] = = ' \' ' )
2009-09-25 22:32:18 +02:00
sizeArgumentAsChar ( tok ) ;
2010-04-02 07:30:58 +02:00
else if ( tokSz - > isNumber ( ) )
2009-01-31 20:29:27 +01:00
{
2010-02-14 19:58:17 +01:00
const std : : string num = tok - > strAt ( 6 ) ;
2010-04-02 07:30:58 +02:00
if ( MathLib : : toLongNumber ( num ) < 0 | | MathLib : : toLongNumber ( num ) > total_size )
2009-01-31 20:29:27 +01:00
{
2010-02-21 15:23:50 +01:00
bufferOverrun ( tok , varnames ) ;
2009-01-31 20:29:27 +01:00
}
}
}
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , ( " memset|memcpy|memmove|memcmp|strncpy|fgets ( " + varnames + " , %num% , %num% ) " ) . c_str ( ) ) | |
Token : : Match ( tok , ( " memcpy|memcmp ( %var% , " + varnames + " , %num% ) " ) . c_str ( ) ) )
2009-01-31 20:29:27 +01:00
{
2010-02-21 15:23:50 +01:00
const std : : string num = tok - > strAt ( varc + 6 ) ;
2010-04-02 07:30:58 +02:00
if ( MathLib : : toLongNumber ( num ) < 0 | | MathLib : : toLongNumber ( num ) > total_size )
2009-01-31 20:29:27 +01:00
{
2010-02-21 15:23:50 +01:00
bufferOverrun ( tok , varnames ) ;
2009-01-31 20:29:27 +01:00
}
continue ;
}
// 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 ;
2009-01-31 20:29:27 +01:00
// for - setup..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > tokAt ( 2 ) - > isNumber ( ) )
2009-08-02 14:26:26 +02:00
{
min_counter_value = tok2 - > strAt ( 2 ) ;
}
counter_varid = tok2 - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-08-02 14:26:26 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %type% %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > tokAt ( 3 ) - > isNumber ( ) )
2009-08-02 14:26:26 +02:00
{
min_counter_value = tok2 - > strAt ( 3 ) ;
}
counter_varid = tok2 - > next ( ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 5 ) ;
2009-08-02 14:26:26 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %type% %type% %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 4 ) - > isNumber ( ) )
2009-08-02 14:26:26 +02:00
{
min_counter_value = tok2 - > strAt ( 4 ) ;
}
counter_varid = tok2 - > tokAt ( 2 ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 6 ) ;
2009-08-02 14:26:26 +02:00
}
2009-01-31 20:29:27 +01:00
else
continue ;
2010-04-02 07:30:58 +02:00
if ( counter_varid = = 0 )
2009-10-03 16:27:16 +02:00
continue ;
2010-04-12 21:04:59 +02:00
bool maxMinFlipped = false ;
2010-02-15 22:20:09 +01:00
const Token * strindextoken = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %varid% < %num% ; " , counter_varid ) )
2009-08-02 14:26:26 +02:00
{
2010-04-12 21:04:59 +02:00
long value = MathLib : : toLongNumber ( tok2 - > strAt ( 2 ) ) ;
2009-10-03 16:27:16 +02:00
max_counter_value = MathLib : : toString < long > ( value - 1 ) ;
2010-02-14 23:10:15 +01:00
strindextoken = tok2 ;
2009-10-03 16:27:16 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %varid% <= %num% ; " , counter_varid ) )
2009-10-03 16:27:16 +02:00
{
max_counter_value = tok2 - > strAt ( 2 ) ;
2010-02-14 23:10:15 +01:00
strindextoken = tok2 ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %num% < %varid% ; " , counter_varid ) )
2010-02-14 23:10:15 +01:00
{
2010-04-12 21:04:59 +02:00
long value = MathLib : : toLongNumber ( tok2 - > str ( ) ) ;
maxMinFlipped = true ;
2010-02-14 23:10:15 +01:00
max_counter_value = min_counter_value ;
min_counter_value = MathLib : : toString < long > ( value + 1 ) ;
strindextoken = tok2 - > tokAt ( 2 ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %num% <= %varid% ; " , counter_varid ) )
2010-02-14 23:10:15 +01:00
{
2010-04-12 21:04:59 +02:00
maxMinFlipped = true ;
2010-02-14 23:10:15 +01:00
max_counter_value = min_counter_value ;
min_counter_value = tok2 - > str ( ) ;
strindextoken = tok2 - > tokAt ( 2 ) ;
2009-08-02 14:26:26 +02:00
}
2010-02-15 22:20:09 +01:00
else
{
continue ;
}
2009-01-31 20:29:27 +01:00
// Get index variable and stopsize.
2010-02-18 22:25:29 +01:00
const std : : string strindex = strindextoken - > str ( ) ;
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
2009-09-27 16:09:41 +02:00
const Token * tok3 = tok2 - > tokAt ( 4 ) ;
assert ( tok3 ! = NULL ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok3 , " %varid% += %num% ) " , counter_varid ) | |
Token : : Match ( tok3 , " %varid% = %num% + %varid% ) " , counter_varid ) )
2009-09-27 16:09:41 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! MathLib : : isInt ( tok3 - > strAt ( 2 ) ) )
2009-10-05 22:19:44 +02:00
continue ;
2010-02-14 19:58:17 +01:00
const int num = MathLib : : toLongNumber ( tok3 - > strAt ( 2 ) ) ;
2009-09-30 14:51:33 +02:00
// 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_counter_value ) ;
long min = MathLib : : toLongNumber ( min_counter_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_counter_value = MathLib : : toString < long > ( max ) ;
2010-04-02 07:30:58 +02:00
if ( max < = size )
2009-09-27 16:09:41 +02:00
condition_out_of_bounds = false ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " %varid% = %varid% + %num% ) " , counter_varid ) )
2009-09-27 16:09:41 +02:00
{
2010-04-02 07:30:58 +02:00
if ( ! MathLib : : isInt ( tok3 - > strAt ( 4 ) ) )
2009-10-05 22:19:44 +02:00
continue ;
2010-02-14 19:58:17 +01:00
const int num = MathLib : : toLongNumber ( tok3 - > strAt ( 4 ) ) ;
2009-09-30 14:51:33 +02:00
long max = MathLib : : toLongNumber ( max_counter_value ) ;
long min = MathLib : : toLongNumber ( min_counter_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_counter_value = MathLib : : toString < long > ( max ) ;
2010-04-02 07:30:58 +02:00
if ( max < = size )
2009-09-27 16:09:41 +02:00
condition_out_of_bounds = false ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " %varid% -= %num% ) " , counter_varid ) | |
Token : : Match ( tok3 , " %varid% = %num% - %varid% ) " , counter_varid ) )
2010-02-14 23:10:15 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! MathLib : : isInt ( tok3 - > strAt ( 2 ) ) )
2010-02-14 23:10:15 +01:00
continue ;
const int num = MathLib : : toLongNumber ( tok3 - > strAt ( 2 ) ) ;
long max = MathLib : : toLongNumber ( max_counter_value ) ;
long min = MathLib : : toLongNumber ( min_counter_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_counter_value = MathLib : : toString < long > ( max ) ;
2010-04-02 07:30:58 +02:00
if ( max < = size )
2010-02-14 23:10:15 +01:00
condition_out_of_bounds = false ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " %varid% = %varid% - %num% ) " , counter_varid ) )
2010-02-14 23:10:15 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! MathLib : : isInt ( tok3 - > strAt ( 4 ) ) )
2010-02-14 23:10:15 +01:00
continue ;
const int num = MathLib : : toLongNumber ( tok3 - > strAt ( 4 ) ) ;
long max = MathLib : : toLongNumber ( max_counter_value ) ;
long min = MathLib : : toLongNumber ( min_counter_value ) ;
max = ( ( max - min ) / num ) * num + min ;
max_counter_value = MathLib : : toString < long > ( max ) ;
2010-04-02 07:30:58 +02:00
if ( max < = size )
2010-02-14 23:10:15 +01:00
condition_out_of_bounds = false ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " --| %varid% --| ) " , counter_varid ) )
2010-04-01 21:35:36 +02:00
{
2010-04-12 21:04:59 +02:00
if ( ! maxMinFlipped & & MathLib : : toLongNumber ( min_counter_value ) < MathLib : : toLongNumber ( max_counter_value ) )
2010-04-01 21:35:36 +02:00
{
// 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_counter_value = min_counter_value ;
min_counter_value = " 0 " ;
}
}
2010-04-02 07:30:58 +02:00
else if ( ! Token : : Match ( tok3 , " ++| %varid% ++| ) " , counter_varid ) )
2009-09-27 17:07:54 +02:00
{
continue ;
}
2009-09-27 16:09:41 +02:00
2009-08-17 22:23:37 +02:00
// Goto the end paranthesis of the for-statement: "for (x; y; z)" ..
tok2 = tok - > next ( ) - > link ( ) ;
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
bool bailOut = false ;
2010-04-02 07:30:58 +02:00
for ( Token * loopTok = tok2 - > next ( ) ; loopTok & & loopTok ! = tok2 - > next ( ) - > link ( ) ; loopTok = loopTok - > next ( ) )
2009-10-01 10:33:53 +02:00
{
2010-04-02 07:30:58 +02:00
if ( loopTok - > varId ( ) = = counter_varid )
2009-10-01 10:33:53 +02:00
{
// Counter variable used inside loop
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( loopTok - > next ( ) , " +=|-=|++|--|= " ) | |
Token : : Match ( loopTok - > previous ( ) , " ++|-- " ) )
2009-10-01 10:33:53 +02:00
{
bailOut = true ;
break ;
}
}
}
2010-04-02 07:30:58 +02:00
if ( bailOut )
2009-10-01 10:33:53 +02:00
{
break ;
}
2009-01-31 20:29:27 +01:00
std : : ostringstream pattern ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 )
2009-10-29 15:04:23 +01:00
pattern < < " %varid% [ " < < strindex < < " ] " ;
else
pattern < < varnames < < " [ " < < strindex < < " ] " ;
2009-01-31 20:29:27 +01:00
int indentlevel2 = 0 ;
2010-04-02 07:30:58 +02:00
while ( ( tok2 = tok2 - > next ( ) ) ! = 0 )
2009-01-31 20:29:27 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ; " & & indentlevel2 = = 0 )
2009-01-31 20:29:27 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-01-31 20:29:27 +01:00
+ + indentlevel2 ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " } " )
2009-01-31 20:29:27 +01:00
{
- - indentlevel2 ;
2010-04-02 07:30:58 +02:00
if ( indentlevel2 < = 0 )
2009-01-31 20:29:27 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " if|switch " ) )
2009-06-29 23:42:46 +02:00
{
// Bailout
break ;
}
2010-04-02 07:30:58 +02:00
if ( condition_out_of_bounds & & Token : : Match ( tok2 , pattern . str ( ) . c_str ( ) , varid ) )
2009-01-31 20:29:27 +01:00
{
2010-02-21 15:23:50 +01:00
bufferOverrun ( tok2 , varid > 0 ? " " : varnames . c_str ( ) ) ;
2009-01-31 20:29:27 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( varid > 0 & & counter_varid > 0 & & ! min_counter_value . empty ( ) & & ! max_counter_value . empty ( ) )
2009-08-02 14:26:26 +02:00
{
int min_index = 0 ;
int max_index = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %varid% [ %var% +|-|*|/ %num% ] " , varid ) & &
tok2 - > tokAt ( 2 ) - > varId ( ) = = counter_varid )
2009-08-02 14:26:26 +02:00
{
2010-02-14 19:58:17 +01:00
const char action = tok2 - > strAt ( 3 ) [ 0 ] ;
2009-08-02 14:26:26 +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());
2009-08-13 22:13:52 +02:00
min_index = std : : atoi ( MathLib : : calculate ( min_counter_value , second , action ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( max_counter_value , second , action ) . c_str ( ) ) ;
2009-08-02 14:26:26 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %varid% [ %num% +|-|*|/ %var% ] " , varid ) & &
tok2 - > tokAt ( 4 ) - > varId ( ) = = counter_varid )
2009-08-02 14:26:26 +02:00
{
2010-02-14 19:58:17 +01:00
const char action = tok2 - > strAt ( 3 ) [ 0 ] ;
2009-08-02 14:26:26 +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());
2009-08-13 22:13:52 +02:00
min_index = std : : atoi ( MathLib : : calculate ( first , min_counter_value , action ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( first , max_counter_value , action ) . c_str ( ) ) ;
2009-08-02 14:26:26 +02:00
}
//printf("min_index = %d, max_index = %d, size = %d\n", min_index, max_index, size);
2010-04-02 07:30:58 +02:00
if ( min_index > = size | | max_index > = size )
2009-08-02 14:26:26 +02:00
{
2009-12-25 15:25:58 +01:00
arrayIndexOutOfBounds ( tok2 , size , min_index > max_index ? min_index : max_index ) ;
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-03-09 12:04:22 +01:00
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-11-20 22:47:06 +01:00
// Writing data into array..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & &
Token : : Match ( tok , " read|write ( %any% , %varid% , %num% ) " , varid ) & &
MathLib : : isInt ( tok - > strAt ( 6 ) ) )
2009-11-20 22:47:06 +01:00
{
2010-03-09 12:04:22 +01:00
long len = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) ;
2010-04-02 07:30:58 +02:00
if ( len < 0 | | len > total_size )
2009-11-20 22:47:06 +01:00
{
bufferOverrun ( tok ) ;
continue ;
}
}
2010-04-06 13:55:03 +02:00
// fread|frwite
// size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
// ptr -> Pointer to a block of memory with a minimum size of (size*count) bytes.
// size -> Size in bytes of each element to be read.
// count -> Number of elements, each one with a size of size bytes.
2010-04-06 15:56:06 +02:00
// stream -> Pointer to a FILE object that specifies an input stream.
2010-04-06 13:55:03 +02:00
if ( varid > 0 & &
Token : : Match ( tok , " fread|fwrite ( %varid% , %num% , %num% , %any% ) " , varid ) & &
MathLib : : isInt ( tok - > strAt ( 6 ) ) )
{
2010-04-06 15:56:06 +02:00
long len = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) * MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) ;
2010-04-06 13:55:03 +02:00
if ( len < 0 | | len > total_size )
{
bufferOverrun ( tok ) ;
continue ;
}
}
2009-11-20 22:47:06 +01:00
// Writing data into array..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & &
Token : : Match ( tok , " fgets ( %varid% , %num% , %any% ) " , varid ) & &
MathLib : : isInt ( tok - > strAt ( 4 ) ) )
2009-11-20 22:47:06 +01:00
{
2010-03-09 12:04:22 +01:00
long len = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
2010-04-02 07:30:58 +02:00
if ( len < 0 | | len > total_size )
2009-11-20 22:47:06 +01:00
{
bufferOverrun ( tok ) ;
continue ;
}
}
2009-02-20 22:00:59 +01:00
// Dangerous usage of strncat..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " strncat ( %varid% , %any% , %num% ) " , varid ) )
2009-02-20 22:00:59 +01:00
{
2010-03-09 11:03:45 +01:00
int n = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) ;
2010-04-02 07:30:58 +02:00
if ( n < 0 | | n > = total_size )
2009-03-21 21:33:27 +01:00
strncatUsage ( tok ) ;
2009-02-20 22:00:59 +01:00
}
2009-02-20 22:16:07 +01:00
// Dangerous usage of strncpy + strncat..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " strncpy|strncat ( %varid% , %any% , %num% ) ; strncat ( %varid% , %any% , %num% ) " , varid ) )
2009-02-20 22:16:07 +01:00
{
2010-03-09 11:03:45 +01:00
int n = MathLib : : toLongNumber ( tok - > strAt ( 6 ) ) + MathLib : : toLongNumber ( tok - > strAt ( 15 ) ) ;
2010-04-02 07:30:58 +02:00
if ( n > total_size )
2009-03-21 21:33:27 +01:00
strncatUsage ( tok - > tokAt ( 9 ) ) ;
2009-02-20 22:16:07 +01:00
}
2009-08-30 13:44:23 +02:00
// Detect few strcat() calls
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
// sprintf..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " sprintf ( %varid% , %str% [,)] " , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-12-05 11:41:30 +01:00
checkSprintfCall ( tok , total_size ) ;
2009-01-31 20:29:27 +01:00
}
// snprintf..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " snprintf ( %varid% , %num% , " , varid ) )
2009-01-31 20:29:27 +01:00
{
2010-02-14 19:58:17 +01:00
int n = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
2010-04-02 07:30:58 +02:00
if ( n > total_size )
2009-03-21 21:33:27 +01:00
outOfBounds ( tok - > tokAt ( 4 ) , " snprintf size " ) ;
2009-01-31 20:29:27 +01:00
}
2009-02-21 13:22:04 +01:00
// cin..
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & Token : : Match ( tok , " cin >> %varid% ; " , varid ) )
2009-02-21 13:22:04 +01:00
{
2009-10-01 09:59:27 +02:00
dangerousStdCin ( tok ) ;
2009-02-21 13:22:04 +01:00
}
2009-01-31 20:29:27 +01:00
// Function call..
// It's not interesting to check what happens when the whole struct is
// sent as the parameter, that is checked separately anyway.
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 ( ) ;
}
}
}
}
//---------------------------------------------------------------------------
// 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-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %type% *| %var% [ %num% ] [;=] " ) )
2009-02-11 17:12:29 +01:00
{
2010-03-09 11:03:45 +01:00
unsigned int varpos = 1 ;
2010-04-02 07:30:58 +02:00
if ( tok - > next ( ) - > str ( ) = = " * " )
2009-06-01 19:21:08 +02:00
+ + varpos ;
2010-02-14 19:58:17 +01:00
size = MathLib : : toLongNumber ( tok - > strAt ( varpos + 2 ) ) ;
2009-06-01 19:21:08 +02:00
type = tok - > strAt ( varpos - 1 ) ;
varid = tok - > tokAt ( varpos ) - > varId ( ) ;
nextTok = varpos + 5 ;
2009-02-11 17:12:29 +01:00
}
2010-04-02 07:30:58 +02:00
else 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 ;
int ivar = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " %type% %var% [ %num% ] ; " ) )
2009-01-31 20:29:27 +01:00
ivar = 2 ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " %type% %type% %var% [ %num% ] ; " ))
2009-01-31 20:29:27 +01:00
ivar = 3 ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " %type% * %var% [ %num% ] ; " ))
2009-01-31 20:29:27 +01:00
ivar = 3 ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " %type% %type% * %var% [ %num% ] ; " ))
2009-01-31 20:29:27 +01:00
ivar = 4 ;
else
continue ;
2010-02-14 19:58:17 +01:00
std : : vector < std : : string > varname ( 2 , " " ) ;
2009-11-12 22:24:44 +01:00
const unsigned int varId = tok2 - > tokAt ( ivar ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
varname [ 1 ] = tok2 - > strAt ( ivar ) ;
2010-02-14 19:58:17 +01:00
int arrsize = MathLib : : toLongNumber ( tok2 - > strAt ( ivar + 2 ) ) ;
2010-03-09 11:03:45 +01:00
int total_size = arrsize * _tokenizer - > sizeOfType ( tok2 - > tokAt ( 1 ) ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > tokAt ( 2 ) - > str ( ) = = " * " )
2010-03-09 11:03:45 +01:00
total_size = arrsize * _tokenizer - > sizeOfType ( tok2 - > tokAt ( 2 ) ) ;
2010-04-02 07:30:58 +02:00
if ( total_size = = 0 )
2009-01-31 20:29:27 +01:00
continue ;
// 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 ;
checkScope ( tok4 - > tokAt ( 2 ) , v , arrsize , total_size , 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..
2009-07-05 22:16:43 +02:00
checkScope ( CheckTok , varname , arrsize , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
}
}
}
}
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : bufferOverrun ( )
2009-01-31 20:29:27 +01:00
{
2009-07-05 22:16:43 +02:00
checkGlobalAndLocalVariable ( ) ;
checkStructVariable ( ) ;
2009-01-31 20:29:27 +01:00
}
//---------------------------------------------------------------------------
2009-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
# include "executionpath.h"
/// @addtogroup Checks
/// @{
class ArrayInfo
{
public :
/** type size in bytes */
unsigned int type_size ;
/** number of elements of array */
unsigned int num ;
} ;
/**
* @ brief % Check for buffer overruns ( using ExecutionPath )
*/
class ExecutionPathBufferOverrun : public ExecutionPath
{
public :
/** Startup constructor */
ExecutionPathBufferOverrun ( Check * c , const std : : map < unsigned int , ArrayInfo > & arrayinfo )
: ExecutionPath ( c , 0 ) , arrayInfo ( arrayinfo )
{
}
private :
/** Copy this check */
ExecutionPath * copy ( )
{
return new ExecutionPathBufferOverrun ( * this ) ;
}
/** @brief buffer information */
const std : : map < unsigned int , ArrayInfo > & arrayInfo ;
/** no implementation => compiler error if used by accident */
void operator = ( const ExecutionPathBufferOverrun & ) ;
/** internal constructor for creating extra checks */
ExecutionPathBufferOverrun ( Check * c , const std : : map < unsigned int , ArrayInfo > & arrayinfo , unsigned int varid_ )
: ExecutionPath ( c , varid_ ) ,
arrayInfo ( arrayinfo )
{
// 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
ArrayInfo ai ;
{
ExecutionPathBufferOverrun * c = dynamic_cast < ExecutionPathBufferOverrun * > ( checks . front ( ) ) ;
std : : map < unsigned int , ArrayInfo > : : const_iterator it ;
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 ) ;
if ( c & & c - > varId = = varid2 & & c - > value > = ai . num )
{
// variable value is out of bounds, report error
CheckBufferOverrun * checkBufferOverrun = dynamic_cast < CheckBufferOverrun * > ( c - > owner ) ;
if ( checkBufferOverrun )
{
checkBufferOverrun - > arrayIndexOutOfBounds ( tok , ai . num , c - > value ) ;
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 ( ) )
{
if ( Token : : Match ( tok , " [;{}] %type% %var% [ %num% ] ; " ) )
{
const unsigned int varid ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
ArrayInfo ai ;
ai . type_size = _tokenizer - > sizeOfType ( tok - > next ( ) ) ;
ai . num = MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) ;
arrayInfo [ varid ] = ai ;
}
}
// Perform checking - check how the arrayInfo arrays are used
ExecutionPathBufferOverrun c ( this , arrayInfo ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
}