2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-01-31 20:29:27 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-31 20:29:27 +01:00
*/
//---------------------------------------------------------------------------
// Buffer overrun..
//---------------------------------------------------------------------------
# include "checkbufferoverrun.h"
2009-02-11 06:16:10 +01:00
# include "tokenize.h"
# include "errorlogger.h"
2009-08-02 14:26:26 +02:00
# include "mathlib.h"
2009-02-11 06:16:10 +01:00
2009-01-31 20:29:27 +01:00
# include <algorithm>
# include <sstream>
# include <list>
# include <cstring>
2009-09-20 12:54:19 +02:00
# include <cctype>
2009-01-31 20:29:27 +01:00
2009-09-27 16:09:41 +02:00
# include <cassert> // <- assert
2009-01-31 20:29:27 +01:00
# include <cstdlib> // <- strtoul
//---------------------------------------------------------------------------
2009-03-20 18:16:21 +01:00
// Register this check class (by creating a static instance of it)
namespace
{
2009-07-13 16:00:15 +02:00
CheckBufferOverrun instance ;
2009-03-20 18:16:21 +01:00
}
//---------------------------------------------------------------------------
2009-01-31 20:29:27 +01:00
2009-10-13 21:39:51 +02:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( const Token * tok , int size )
2009-01-31 20:29:27 +01:00
{
2009-08-04 21:36:55 +02:00
if ( ! tok )
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( size ) ;
2009-08-04 21:36:55 +02:00
else
{
_callStack . push_back ( tok ) ;
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( size ) ;
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-10-13 21:39:51 +02:00
void CheckBufferOverrun : : arrayIndexOutOfBounds ( int size )
2009-03-21 21:33:27 +01:00
{
2009-10-13 21:39:51 +02:00
Severity : : e severity ;
2009-10-13 22:33:41 +02:00
if ( size < = 1 | | _callStack . size ( ) > 1 )
2009-10-13 21:39:51 +02:00
{
severity = Severity : : possibleError ;
if ( _settings - > _showAll = = false )
return ;
}
else
{
severity = Severity : : error ;
}
reportError ( _callStack , severity , " arrayIndexOutOfBounds " , " Array index out of bounds " ) ;
2009-03-21 21:33:27 +01:00
}
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : bufferOverrun ( const Token * tok )
2009-03-21 21:33:27 +01:00
{
2009-10-13 23:09:37 +02:00
Severity : : e severity ;
if ( _callStack . size ( ) > 0 )
{
severity = Severity : : possibleError ;
if ( _settings - > _showAll = = false )
return ;
}
else
{
severity = Severity : : error ;
}
2009-10-15 19:36:48 +02:00
reportError ( tok , severity , " bufferAccessOutOfBounds " , " Buffer access out-of-bounds " ) ;
2009-03-21 21:33:27 +01:00
}
2009-10-01 09:59:27 +02:00
void CheckBufferOverrun : : dangerousStdCin ( const Token * tok )
{
2009-10-17 20:13:09 +02:00
if ( _settings & & _settings - > _showAll = = 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
{
2009-10-17 20:13:09 +02:00
if ( _settings & & _settings - > _showAll = = 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
{
2009-10-17 20:13:09 +02:00
if ( _settings & & _settings - > _showAll = = 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-01-31 20:29:27 +01:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check array usage..
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : checkScope ( const Token * tok , const char * varname [ ] , const int size , const int total_size , unsigned int varid )
2009-01-31 20:29:27 +01:00
{
unsigned int varc = 0 ;
std : : string varnames ;
2009-10-28 21:42:54 +01:00
while ( varname & & varname [ varc ] )
2009-01-31 20:29:27 +01:00
{
if ( varc > 0 )
varnames + = " . " ;
varnames + = varname [ varc ] ;
+ + varc ;
}
if ( varc = = 0 )
varc = 1 ;
varc = 2 * ( varc - 1 ) ;
// Array index..
2009-10-28 21:49:46 +01:00
if ( varid > 0 )
2009-01-31 20:29:27 +01:00
{
if ( Token : : Match ( tok , " %varid% [ %num% ] " , varid ) )
{
const char * num = tok - > strAt ( 2 ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( tok - > next ( ) , size ) ;
2009-01-31 20:29:27 +01:00
}
}
}
else if ( Token : : Match ( tok , std : : string ( varnames + " [ %num% ] " ) . c_str ( ) ) )
{
const char * num = tok - > strAt ( 2 + varc ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( tok - > next ( ) , size ) ;
2009-01-31 20:29:27 +01:00
}
}
int indentlevel = 0 ;
for ( ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < 0 )
return ;
}
// Array index..
if ( varid > 0 )
{
if ( ! tok - > isName ( ) & & ! Token : : Match ( tok , " [.&] " ) & & Token : : Match ( tok - > next ( ) , " %varid% [ %num% ] " , varid ) )
{
const char * num = tok - > strAt ( 3 ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-10-06 13:50:27 +02:00
if ( std : : strtol ( num , NULL , 10 ) > size | | ! Token : : Match ( tok - > previous ( ) , " & ( " ) )
{
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( tok - > next ( ) , size ) ;
2009-10-06 13:50:27 +02:00
}
2009-01-31 20:29:27 +01:00
}
}
}
else if ( ! tok - > isName ( ) & & ! Token : : Match ( tok , " [.&] " ) & & Token : : Match ( tok - > next ( ) , std : : string ( varnames + " [ %num% ] " ) . c_str ( ) ) )
{
const char * num = tok - > next ( ) - > strAt ( 2 + varc ) ;
if ( std : : strtol ( num , NULL , 10 ) > = size )
{
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( tok - > next ( ) , size ) ;
2009-01-31 20:29:27 +01:00
}
tok = tok - > tokAt ( 4 ) ;
continue ;
}
// memset, memcmp, memcpy, strncpy, fgets..
if ( varid > 0 )
{
2009-09-25 22:32:18 +02:00
if ( Token : : Match ( tok , " memset|memcpy|memmove|memcmp|strncpy|fgets ( %varid% , %any% , %any% ) " , varid ) | |
Token : : Match ( tok , " memset|memcpy|memmove|memcmp|fgets ( %var% , %varid% , %any% ) " , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
const Token * tokSz = tok - > tokAt ( 6 ) ;
if ( tokSz - > str ( ) [ 0 ] = = ' \' ' )
sizeArgumentAsChar ( tok ) ;
else if ( tokSz - > isNumber ( ) )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
const char * num = tok - > strAt ( 6 ) ;
if ( std : : atoi ( num ) > total_size )
2009-01-31 20:29:27 +01:00
{
2009-09-25 22:32:18 +02:00
bufferOverrun ( tok ) ;
2009-01-31 20:29:27 +01:00
}
}
}
}
else if ( Token : : Match ( tok , " memset|memcpy|memmove|memcmp|strncpy|fgets " ) )
{
if ( Token : : Match ( tok - > next ( ) , std : : string ( " ( " + varnames + " , %num% , %num% ) " ) . c_str ( ) ) | |
Token : : Match ( tok - > next ( ) , std : : string ( " ( %var% , " + varnames + " , %num% ) " ) . c_str ( ) ) )
{
const char * num = tok - > strAt ( varc + 6 ) ;
if ( std : : atoi ( num ) > total_size )
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok ) ;
2009-01-31 20:29:27 +01:00
}
}
continue ;
}
// Loop..
if ( Token : : simpleMatch ( tok , " for ( " ) )
{
const Token * tok2 = tok - > tokAt ( 2 ) ;
2009-08-02 14:26:26 +02:00
unsigned int counter_varid = 0 ;
std : : string min_counter_value ;
std : : string max_counter_value ;
2009-01-31 20:29:27 +01:00
// for - setup..
2009-04-04 20:05:48 +02:00
if ( Token : : Match ( tok2 , " %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
if ( tok2 - > tokAt ( 2 ) - > isNumber ( ) )
{
min_counter_value = tok2 - > strAt ( 2 ) ;
}
counter_varid = tok2 - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-08-02 14:26:26 +02:00
}
2009-04-04 20:05:48 +02:00
else if ( Token : : Match ( tok2 , " %type% %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
if ( tok2 - > tokAt ( 3 ) - > isNumber ( ) )
{
min_counter_value = tok2 - > strAt ( 3 ) ;
}
counter_varid = tok2 - > next ( ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 5 ) ;
2009-08-02 14:26:26 +02:00
}
2009-04-04 20:05:48 +02:00
else if ( Token : : Match ( tok2 , " %type% %type% %var% = %any% ; " ) )
2009-08-02 14:26:26 +02:00
{
if ( tok - > tokAt ( 4 ) - > isNumber ( ) )
{
min_counter_value = tok2 - > strAt ( 4 ) ;
}
counter_varid = tok2 - > tokAt ( 2 ) - > varId ( ) ;
2009-01-31 20:29:27 +01:00
tok2 = tok2 - > tokAt ( 6 ) ;
2009-08-02 14:26:26 +02:00
}
2009-01-31 20:29:27 +01:00
else
continue ;
2009-09-27 16:09:41 +02:00
int value = 0 ;
2009-10-03 16:27:16 +02:00
if ( counter_varid = = 0 )
continue ;
if ( Token : : Match ( tok2 , " %varid% < %num% ; " , counter_varid ) )
2009-08-02 14:26:26 +02:00
{
2009-10-03 16:27:16 +02:00
value = std : : atoi ( tok2 - > strAt ( 2 ) ) ;
max_counter_value = MathLib : : toString < long > ( value - 1 ) ;
}
else if ( Token : : Match ( tok2 , " %varid% <= %num% ; " , counter_varid ) )
{
value = std : : atoi ( tok2 - > strAt ( 2 ) ) + 1 ;
max_counter_value = tok2 - > strAt ( 2 ) ;
2009-08-02 14:26:26 +02:00
}
2009-01-31 20:29:27 +01:00
// Get index variable and stopsize.
2009-05-03 20:10:59 +02:00
const char * strindex = tok2 - > str ( ) . c_str ( ) ;
2009-08-02 15:34:28 +02:00
bool condition_out_of_bounds = true ;
2009-09-27 17:50:59 +02:00
if ( value < = size )
2009-09-27 17:11:57 +02:00
condition_out_of_bounds = false ;
2009-01-31 20:29:27 +01:00
2009-09-27 16:09:41 +02:00
const Token * tok3 = tok2 - > tokAt ( 4 ) ;
assert ( tok3 ! = NULL ) ;
if ( Token : : Match ( tok3 , " %varid% += %num% ) " , counter_varid ) | |
Token : : Match ( tok3 , " %varid% = %num% + %varid% ) " , counter_varid ) )
{
2009-10-05 22:19:44 +02:00
if ( ! MathLib : : isInt ( tok3 - > strAt ( 2 ) ) )
continue ;
2009-09-27 16:09:41 +02:00
const int num = std : : atoi ( 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 ) ;
if ( max < = size )
2009-09-27 16:09:41 +02:00
condition_out_of_bounds = false ;
}
else if ( Token : : Match ( tok3 , " %varid% = %varid% + %num% ) " , counter_varid ) )
{
2009-10-05 22:19:44 +02:00
if ( ! MathLib : : isInt ( tok3 - > strAt ( 4 ) ) )
continue ;
2009-09-27 16:09:41 +02:00
const int num = std : : atoi ( 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 ) ;
if ( max < = size )
2009-09-27 16:09:41 +02:00
condition_out_of_bounds = false ;
}
2009-09-27 17:07:54 +02:00
else if ( ! Token : : Match ( tok3 , " ++| %varid% ++| ) " , counter_varid ) )
{
continue ;
}
2009-09-27 16:09:41 +02:00
2009-08-17 22:23:37 +02:00
// Goto the end paranthesis of the for-statement: "for (x; y; z)" ..
tok2 = tok - > next ( ) - > link ( ) ;
2009-01-31 20:29:27 +01:00
if ( ! tok2 | | ! tok2 - > tokAt ( 5 ) )
break ;
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 ;
for ( Token * loopTok = tok2 - > next ( ) ; loopTok & & loopTok ! = tok2 - > next ( ) - > link ( ) ; loopTok = loopTok - > next ( ) )
{
if ( loopTok - > varId ( ) = = counter_varid )
{
// Counter variable used inside loop
2009-10-01 10:37:15 +02:00
if ( Token : : Match ( loopTok - > next ( ) , " +=|-=|++|--|= " ) | |
Token : : Match ( loopTok - > previous ( ) , " ++|-- " ) )
2009-10-01 10:33:53 +02:00
{
bailOut = true ;
break ;
}
}
}
if ( bailOut )
{
break ;
}
2009-01-31 20:29:27 +01:00
std : : ostringstream pattern ;
2009-10-29 15:04:23 +01:00
if ( varid > 0 )
pattern < < " %varid% [ " < < strindex < < " ] " ;
else
pattern < < varnames < < " [ " < < strindex < < " ] " ;
2009-01-31 20:29:27 +01:00
int indentlevel2 = 0 ;
2009-09-13 09:03:48 +02:00
while ( ( tok2 = tok2 - > next ( ) ) ! = 0 )
2009-01-31 20:29:27 +01:00
{
if ( tok2 - > str ( ) = = " ; " & & indentlevel2 = = 0 )
break ;
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
if ( tok2 - > str ( ) = = " } " )
{
- - indentlevel2 ;
if ( indentlevel2 < = 0 )
break ;
}
2009-06-29 23:42:46 +02:00
if ( tok2 - > str ( ) = = " if " )
{
// Bailout
break ;
}
2009-10-29 15:04:23 +01:00
if ( condition_out_of_bounds & & Token : : Match ( tok2 , pattern . str ( ) . c_str ( ) , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok2 ) ;
2009-01-31 20:29:27 +01:00
break ;
}
2009-08-02 15:01:59 +02:00
else if ( varid > 0 & & counter_varid > 0 & & ! min_counter_value . empty ( ) & & ! max_counter_value . empty ( ) )
2009-08-02 14:26:26 +02:00
{
int min_index = 0 ;
int max_index = 0 ;
if ( Token : : Match ( tok2 , " %varid% [ %var% +|-|*|/ %num% ] " , varid ) & &
tok2 - > tokAt ( 2 ) - > varId ( ) = = counter_varid )
{
char action = * ( tok2 - > strAt ( 3 ) ) ;
const std : : string & second ( tok2 - > tokAt ( 4 ) - > str ( ) ) ;
//printf("min_index: %s %c %s\n", min_counter_value.c_str(), action, second.c_str());
//printf("max_index: %s %c %s\n", max_counter_value.c_str(), action, second.c_str());
2009-08-13 22:13:52 +02:00
min_index = std : : atoi ( MathLib : : calculate ( min_counter_value , second , action ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( max_counter_value , second , action ) . c_str ( ) ) ;
2009-08-02 14:26:26 +02:00
}
else if ( Token : : Match ( tok2 , " %varid% [ %num% +|-|*|/ %var% ] " , varid ) & &
tok2 - > tokAt ( 4 ) - > varId ( ) = = counter_varid )
{
char action = * ( tok2 - > strAt ( 3 ) ) ;
const std : : string & first ( tok2 - > tokAt ( 2 ) - > str ( ) ) ;
//printf("min_index: %s %c %s\n", first.c_str(), action, min_counter_value.c_str());
//printf("max_index: %s %c %s\n", first.c_str(), action, max_counter_value.c_str());
2009-08-13 22:13:52 +02:00
min_index = std : : atoi ( MathLib : : calculate ( first , min_counter_value , action ) . c_str ( ) ) ;
max_index = std : : atoi ( MathLib : : calculate ( first , max_counter_value , action ) . c_str ( ) ) ;
2009-08-02 14:26:26 +02:00
}
//printf("min_index = %d, max_index = %d, size = %d\n", min_index, max_index, size);
if ( min_index > = size | | max_index > = size )
{
2009-10-13 21:39:51 +02:00
arrayIndexOutOfBounds ( tok2 - > next ( ) , size ) ;
2009-08-02 14:26:26 +02:00
}
}
2009-01-31 20:29:27 +01:00
}
continue ;
}
// Writing data into array..
2009-10-28 21:42:54 +01: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
{
2009-08-30 13:21:42 +02:00
size_t len = Token : : getStrLength ( tok - > tokAt ( varc + 4 ) ) ;
if ( len > = static_cast < size_t > ( size ) )
2009-01-31 20:29:27 +01:00
{
2009-03-21 21:33:27 +01:00
bufferOverrun ( tok ) ;
2009-08-30 13:44:23 +02:00
continue ;
2009-01-31 20:29:27 +01:00
}
}
2009-02-20 22:16:07 +01:00
2009-02-20 22:00:59 +01:00
// Dangerous usage of strncat..
2009-03-05 18:28:59 +01:00
if ( varid > 0 & & Token : : Match ( tok , " strncat ( %varid% , %any% , %num% ) " , varid ) )
2009-02-20 22:00:59 +01:00
{
2009-08-13 22:13:52 +02:00
int n = std : : atoi ( tok - > strAt ( 6 ) ) ;
2009-07-11 12:16:38 +02:00
if ( n > = ( size - 1 ) )
2009-03-21 21:33:27 +01:00
strncatUsage ( tok ) ;
2009-02-20 22:00:59 +01:00
}
2009-02-20 22:16:07 +01:00
// Dangerous usage of strncpy + strncat..
2009-03-05 18:28:59 +01:00
if ( varid > 0 & & Token : : Match ( tok , " strncpy|strncat ( %varid% , %any% , %num% ) ; strncat ( %varid% , %any% , %num% ) " , varid ) )
2009-02-20 22:16:07 +01:00
{
2009-08-13 22:13:52 +02:00
int n = std : : atoi ( tok - > strAt ( 6 ) ) + std : : atoi ( tok - > strAt ( 15 ) ) ;
2009-02-20 22:16:07 +01:00
if ( n > size )
2009-03-21 21:33:27 +01:00
strncatUsage ( tok - > tokAt ( 9 ) ) ;
2009-02-20 22:16:07 +01:00
}
2009-08-30 13:44:23 +02:00
// Detect few strcat() calls
if ( varid > 0 & & Token : : Match ( tok , " strcat ( %varid% , %str% ) ; " , varid ) )
{
size_t charactersAppend = 0 ;
const Token * tok2 = tok ;
while ( tok2 & & Token : : Match ( tok2 , " strcat ( %varid% , %str% ) ; " , varid ) )
{
charactersAppend + = Token : : getStrLength ( tok2 - > tokAt ( 4 ) ) ;
if ( charactersAppend > = static_cast < size_t > ( size ) )
{
bufferOverrun ( tok2 ) ;
break ;
}
tok2 = tok2 - > tokAt ( 7 ) ;
}
}
2009-01-31 20:29:27 +01:00
// sprintf..
2009-08-08 16:52:35 +02:00
if ( varid > 0 & & Token : : Match ( tok , " sprintf ( %varid% , %str% [,)] " , varid ) )
2009-01-31 20:29:27 +01:00
{
2009-10-07 14:37:20 +02:00
checkSprintfCall ( tok , size ) ;
2009-01-31 20:29:27 +01:00
}
// snprintf..
2009-03-24 18:43:39 +01:00
if ( varid > 0 & & Token : : Match ( tok , " snprintf ( %varid% , %num% , " , varid ) )
2009-01-31 20:29:27 +01:00
{
int n = std : : atoi ( tok - > strAt ( 4 ) ) ;
if ( n > size )
2009-03-21 21:33:27 +01:00
outOfBounds ( tok - > tokAt ( 4 ) , " snprintf size " ) ;
2009-01-31 20:29:27 +01:00
}
2009-02-21 13:22:04 +01:00
// cin..
if ( varid > 0 & & Token : : Match ( tok , " cin >> %varid% ; " , varid ) )
{
2009-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.
if ( Token : : Match ( tok , " %var% ( " ) )
{
// Don't make recursive checking..
if ( std : : find ( _callStack . begin ( ) , _callStack . end ( ) , tok ) ! = _callStack . end ( ) )
continue ;
// Only perform this checking if showAll setting is enabled..
2009-03-20 17:35:53 +01:00
if ( ! _settings - > _showAll )
2009-01-31 20:29:27 +01:00
continue ;
unsigned int parlevel = 0 , par = 0 ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
{
+ + parlevel ;
}
else if ( tok2 - > str ( ) = = " ) " )
{
- - parlevel ;
if ( parlevel < 1 )
{
par = 0 ;
break ;
}
}
else if ( parlevel = = 1 & & ( tok2 - > str ( ) = = " , " ) )
{
+ + par ;
}
2009-10-28 21:42:54 +01:00
if ( parlevel = = 1 )
2009-01-31 20:29:27 +01:00
{
2009-10-28 21:42:54 +01:00
if ( ( varid > 0 & & Token : : Match ( tok2 , std : : string ( " [(,] %varid% [,)] " ) . c_str ( ) , varid ) ) | |
( varid = = 0 & & Token : : Match ( tok2 , std : : string ( " [(,] " + varnames + " [,)] " ) . c_str ( ) ) ) )
{
+ + par ;
break ;
}
2009-01-31 20:29:27 +01:00
}
}
if ( par = = 0 )
continue ;
// Find function..
2009-07-05 22:16:43 +02:00
const Token * ftok = _tokenizer - > getFunctionTokenByName ( tok - > str ( ) . c_str ( ) ) ;
2009-01-31 20:29:27 +01:00
if ( ! ftok )
continue ;
// Parse head of function..
ftok = ftok - > tokAt ( 2 ) ;
parlevel = 1 ;
while ( ftok & & parlevel = = 1 & & par > = 1 )
{
if ( ftok - > str ( ) = = " ( " )
+ + parlevel ;
else if ( ftok - > str ( ) = = " ) " )
- - parlevel ;
else if ( ftok - > str ( ) = = " , " )
- - par ;
else if ( par = = 1 & & parlevel = = 1 & & Token : : Match ( ftok , " %var% [,)] " ) )
{
// Parameter name..
const char * parname [ 2 ] ;
2009-05-03 20:10:59 +02:00
parname [ 0 ] = ftok - > str ( ) . c_str ( ) ;
2009-01-31 20:29:27 +01:00
parname [ 1 ] = 0 ;
// Goto function body..
while ( ftok & & ( ftok - > str ( ) ! = " { " ) )
ftok = ftok - > next ( ) ;
ftok = ftok ? ftok - > next ( ) : 0 ;
// Check variable usage in the function..
_callStack . push_back ( tok ) ;
2009-07-05 22:16:43 +02:00
checkScope ( ftok , parname , size , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
_callStack . pop_back ( ) ;
// break out..
break ;
}
ftok = ftok - > next ( ) ;
}
}
}
}
//---------------------------------------------------------------------------
// Checking local variables in a scope
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : checkGlobalAndLocalVariable ( )
2009-01-31 20:29:27 +01:00
{
int indentlevel = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
- - indentlevel ;
2009-02-11 17:12:29 +01:00
unsigned int size = 0 ;
const char * type = 0 ;
unsigned int varid = 0 ;
int nextTok = 0 ;
2009-01-31 20:29:27 +01:00
2009-06-02 18:56:53 +02:00
// if the previous token exists, it must be either a variable name or "[;{}]"
if ( tok - > previous ( ) & & ( ! tok - > previous ( ) - > isName ( ) & & ! Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) )
continue ;
2009-06-01 19:21:08 +02:00
if ( Token : : Match ( tok , " %type% *| %var% [ %num% ] [;=] " ) )
2009-02-11 17:12:29 +01:00
{
2009-06-01 19:21:08 +02:00
unsigned int varpos = 1 ;
if ( tok - > next ( ) - > str ( ) = = " * " )
+ + varpos ;
size = std : : strtoul ( tok - > strAt ( varpos + 2 ) , NULL , 10 ) ;
type = tok - > strAt ( varpos - 1 ) ;
varid = tok - > tokAt ( varpos ) - > varId ( ) ;
nextTok = varpos + 5 ;
2009-02-11 17:12:29 +01:00
}
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = new %type% [ %num% ] " ) )
{
size = std : : strtoul ( tok - > strAt ( 6 ) , NULL , 10 ) ;
type = tok - > strAt ( 4 ) ;
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 8 ;
}
2009-03-16 18:11:09 +01:00
else if ( indentlevel > 0 & & Token : : Match ( tok , " [*;{}] %var% = malloc ( %num% ) ; " ) )
{
size = std : : strtoul ( tok - > strAt ( 5 ) , NULL , 10 ) ;
type = " char " ;
varid = tok - > tokAt ( 1 ) - > varId ( ) ;
nextTok = 7 ;
}
2009-02-11 17:12:29 +01:00
else
{
continue ;
}
2009-01-31 20:29:27 +01:00
2009-11-06 23:58:33 +01:00
if ( varid = = 0 )
continue ;
2009-10-07 09:54:34 +02:00
Token sizeTok ;
sizeTok . str ( type ) ;
2009-10-27 19:23:45 +01:00
int total_size = size * _tokenizer - > sizeOfType ( & sizeTok ) ;
2009-02-11 17:12:29 +01:00
if ( total_size = = 0 )
continue ;
2009-01-31 20:29:27 +01:00
2009-02-11 17:12:29 +01:00
// The callstack is empty
_callStack . clear ( ) ;
2009-10-28 21:42:54 +01:00
checkScope ( tok - > tokAt ( nextTok ) , 0 , size , total_size , varid ) ;
2009-01-31 20:29:27 +01:00
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Checking member variables of structs..
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : checkStructVariable ( )
2009-01-31 20:29:27 +01:00
{
const char declstruct [ ] = " struct|class %var% { " ;
for ( const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , declstruct ) ;
tok ; tok = Token : : findmatch ( tok - > next ( ) , declstruct ) )
{
const std : : string & structname = tok - > next ( ) - > str ( ) ;
// Found a struct declaration. Search for arrays..
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " } " )
break ;
int ivar = 0 ;
if ( Token : : Match ( tok2 - > next ( ) , " %type% %var% [ %num% ] ; " ) )
ivar = 2 ;
else if ( Token : : Match ( tok2 - > next ( ) , " %type% %type% %var% [ %num% ] ; " ))
ivar = 3 ;
else if ( Token : : Match ( tok2 - > next ( ) , " %type% * %var% [ %num% ] ; " ))
ivar = 3 ;
else if ( Token : : Match ( tok2 - > next ( ) , " %type% %type% * %var% [ %num% ] ; " ))
ivar = 4 ;
else
continue ;
const char * varname [ 3 ] = { 0 , 0 , 0 } ;
varname [ 1 ] = tok2 - > strAt ( ivar ) ;
int arrsize = std : : atoi ( tok2 - > strAt ( ivar + 2 ) ) ;
2009-10-07 09:54:34 +02:00
int total_size = arrsize * _tokenizer - > sizeOfType ( tok2 - > tokAt ( 1 ) ) ;
2009-01-31 20:29:27 +01:00
if ( total_size = = 0 )
continue ;
// Class member variable => Check functions
if ( tok - > str ( ) = = " class " )
{
std : : string func_pattern ( structname + " :: %var% ( " ) ;
const Token * tok3 = Token : : findmatch ( _tokenizer - > tokens ( ) , func_pattern . c_str ( ) ) ;
while ( tok3 )
{
for ( const Token * tok4 = tok3 ; tok4 ; tok4 = tok4 - > next ( ) )
{
if ( Token : : Match ( tok4 , " [;{}] " ) )
break ;
if ( Token : : simpleMatch ( tok4 , " ) { " ) )
{
const char * names [ 2 ] = { varname [ 1 ] , 0 } ;
2009-07-05 22:16:43 +02:00
checkScope ( tok4 - > tokAt ( 2 ) , names , arrsize , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
break ;
}
}
tok3 = Token : : findmatch ( tok3 - > next ( ) , func_pattern . c_str ( ) ) ;
}
}
for ( const Token * tok3 = _tokenizer - > tokens ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) ! = structname )
continue ;
// Declare variable: Fred fred1;
if ( Token : : Match ( tok3 - > next ( ) , " %var% ; " ) )
varname [ 0 ] = tok3 - > strAt ( 1 ) ;
// Declare pointer: Fred *fred1
else if ( Token : : Match ( tok3 - > next ( ) , " * %var% [,) ; = ] " ))
varname [ 0 ] = tok3 - > strAt ( 2 ) ;
else
continue ;
// Goto end of statement.
const Token * CheckTok = NULL ;
while ( tok3 )
{
// End of statement.
if ( tok3 - > str ( ) = = " ; " )
{
CheckTok = tok3 ;
break ;
}
// End of function declaration..
if ( Token : : simpleMatch ( tok3 , " ) ; " ) )
break ;
// Function implementation..
if ( Token : : simpleMatch ( tok3 , " ) { " ) )
{
CheckTok = tok3 - > tokAt ( 2 ) ;
break ;
}
tok3 = tok3 - > next ( ) ;
}
if ( ! tok3 )
break ;
if ( ! CheckTok )
continue ;
// Check variable usage..
2009-07-05 22:16:43 +02:00
checkScope ( CheckTok , varname , arrsize , total_size , 0 ) ;
2009-01-31 20:29:27 +01:00
}
}
}
}
//---------------------------------------------------------------------------
2009-07-13 16:00:15 +02:00
void CheckBufferOverrun : : bufferOverrun ( )
2009-01-31 20:29:27 +01:00
{
2009-07-05 22:16:43 +02:00
checkGlobalAndLocalVariable ( ) ;
checkStructVariable ( ) ;
2009-01-31 20:29:27 +01:00
}
//---------------------------------------------------------------------------
2009-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 ( ) ;
2009-10-11 21:07:18 +02:00
unsigned int parameterLength = 0 ;
2009-10-18 12:58:48 +02:00
for ( std : : string : : size_type i = 0 ; i < input_string . length ( ) ; + + i )
2009-09-25 18:23:44 +02:00
{
2009-10-18 12:58:48 +02:00
if ( input_string [ i ] = = ' \\ ' )
2009-09-25 18:23:44 +02:00
{
2009-10-18 12:58:48 +02:00
if ( input_string [ i + 1 ] = = ' 0 ' )
break ;
+ + input_string_size ;
+ + i ;
continue ;
2009-09-25 18:23:44 +02:00
}
2009-10-18 12:58:48 +02:00
if ( percentCharFound )
2009-09-25 18:23:44 +02:00
{
2009-10-18 12:58:48 +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 ;
if ( paramIter ! = parameters . end ( ) & & * paramIter & & ( * paramIter ) - > str ( ) [ 0 ] ! = ' " ' )
parameterLength = ( * paramIter ) - > str ( ) . length ( ) ;
2009-10-18 12:58:48 +02:00
handleNextParameter = true ;
break ;
case ' s ' :
2009-10-08 15:27:46 +02:00
if ( paramIter ! = parameters . end ( ) & & * paramIter & & ( * paramIter ) - > str ( ) [ 0 ] = = ' " ' )
parameterLength = Token : : getStrLength ( * paramIter ) ;
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
2009-10-18 12:58:48 +02:00
if ( input_string [ i ] = = ' % ' )
percentCharFound = ! percentCharFound ;
else if ( percentCharFound )
{
digits_string . append ( 1 , input_string [ i ] ) ;
2009-09-25 18:23:44 +02:00
}
2009-10-18 12:58:48 +02:00
if ( ! percentCharFound )
input_string_size + + ;
2009-09-25 18:23:44 +02:00
2009-10-18 12:58:48 +02:00
if ( handleNextParameter )
2009-09-25 18:23:44 +02:00
{
2009-10-18 12:58:48 +02:00
unsigned int tempDigits = std : : abs ( std : : atoi ( digits_string . c_str ( ) ) ) ;
if ( i_d_x_f_found )
tempDigits = std : : max ( static_cast < int > ( tempDigits ) , 1 ) ;
2009-10-08 15:27:46 +02:00
2009-10-19 23:48:29 +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 ) ;
unsigned int maxLen = std : : max ( std : : abs ( std : : atoi ( endStr . c_str ( ) ) ) , 1 ) ;
2009-10-19 23:48:29 +02:00
if ( input_string [ i ] = = ' s ' )
{
// For strings, the length after the dot "%.2s" will limit
// the length of the string.
if ( parameterLength > maxLen )
parameterLength = maxLen ;
}
else
{
// For integers, the length after the dot "%.2d" can
// increase required length
if ( tempDigits < maxLen )
tempDigits = maxLen ;
}
2009-10-11 21:07:18 +02:00
}
2009-10-08 15:27:46 +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 ;
2009-10-19 23:55:20 +02:00
if ( paramIter ! = parameters . end ( ) )
+ + 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 ;
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 ( ) ;
for ( const Token * tok2 = tok - > tokAt ( 5 ) ; tok2 & & tok2 ! = end ; tok2 = tok2 - > next ( ) )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
if ( Token : : Match ( tok2 , " , %any% [,)] " ) )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " %str% " ) )
parameters . push_back ( tok2 - > next ( ) ) ;
2009-10-07 14:37:20 +02:00
2009-10-11 20:36:22 +02:00
else if ( Token : : Match ( tok2 - > next ( ) , " %num% " ) )
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 ;
for ( const Token * tok3 = tok2 - > next ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
if ( tok3 - > str ( ) = = " ( " )
+ + ind ;
2009-10-07 14:37:20 +02:00
2009-10-11 20:36:22 +02:00
else if ( tok3 - > str ( ) = = " ) " )
2009-10-07 14:37:20 +02:00
{
2009-10-11 20:36:22 +02:00
- - ind ;
if ( ind < 0 )
break ;
2009-10-07 14:37:20 +02:00
}
2009-10-11 20:36:22 +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
if ( ind < 0 )
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 ) ;
if ( len > size )
{
bufferOverrun ( tok ) ;
}
2009-10-07 14:37:20 +02:00
}