2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2014-02-15 07:45:39 +01:00
* Copyright ( C ) 2007 - 2014 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
*/
//---------------------------------------------------------------------------
2013-09-04 20:59:49 +02:00
# ifndef checkbufferoverrunH
# define checkbufferoverrunH
2009-01-31 20:29:27 +01:00
//---------------------------------------------------------------------------
2012-06-10 14:19:09 +02:00
# include "config.h"
2009-03-20 17:35:53 +01:00
# include "check.h"
2010-11-21 11:48:27 +01:00
# include "mathlib.h"
2009-02-11 06:16:10 +01:00
# include <list>
2010-02-14 19:58:17 +01:00
# include <vector>
# include <string>
2009-02-11 06:16:10 +01:00
2011-06-23 04:44:11 +02:00
class Variable ;
2009-01-31 20:29:27 +01:00
2009-07-17 10:49:01 +02:00
/// @addtogroup Checks
/// @{
2010-03-13 21:42:59 +01:00
/**
* @ brief buffer overruns and array index out of bounds
*
* Buffer overrun and array index out of bounds are pretty much the same .
* But I generally use ' array index ' if the code contains [ ] . And the given
* index is out of bounds .
* I generally use ' buffer overrun ' if you for example call a strcpy or
* other function and pass a buffer and reads or writes too much data .
*/
2012-06-10 14:19:09 +02:00
class CPPCHECKLIB CheckBufferOverrun : public Check {
2009-01-31 20:29:27 +01:00
public :
2009-03-20 17:35:53 +01:00
2009-03-21 07:53:23 +01:00
/** This constructor is used when registering the CheckClass */
2014-11-20 14:20:09 +01:00
CheckBufferOverrun ( ) : Check ( myName ( ) ) {
2013-08-07 16:27:37 +02:00
}
2009-03-20 17:35:53 +01:00
2010-03-17 22:16:18 +01:00
/** This constructor is used when running checks. */
2009-07-13 16:00:15 +02:00
CheckBufferOverrun ( const Tokenizer * tokenizer , const Settings * settings , ErrorLogger * errorLogger )
2014-11-20 14:20:09 +01:00
: Check ( myName ( ) , tokenizer , settings , errorLogger ) {
2013-08-07 16:27:37 +02:00
}
2009-03-20 17:35:53 +01:00
2014-11-20 14:20:09 +01:00
void runSimplifiedChecks ( const Tokenizer * tokenizer , const Settings * settings , ErrorLogger * errorLogger ) {
2009-07-13 16:00:15 +02:00
CheckBufferOverrun checkBufferOverrun ( tokenizer , settings , errorLogger ) ;
2009-10-13 21:39:51 +02:00
checkBufferOverrun . bufferOverrun ( ) ;
2014-06-26 17:36:20 +02:00
checkBufferOverrun . bufferOverrun2 ( ) ;
2011-08-04 11:15:14 +02:00
checkBufferOverrun . arrayIndexThenCheck ( ) ;
2013-03-19 08:22:48 +01:00
checkBufferOverrun . writeOutsideBufferSize ( ) ;
2009-03-20 17:35:53 +01:00
}
2009-01-31 20:29:27 +01:00
2010-03-13 21:42:59 +01:00
/** @brief %Check for buffer overruns */
2009-01-31 20:29:27 +01:00
void bufferOverrun ( ) ;
2010-03-13 21:42:59 +01:00
2014-06-26 17:36:20 +02:00
/** @brief %Check for buffer overruns #2 (single pass, use ast and valueflow) */
void bufferOverrun2 ( ) ;
2011-08-04 11:15:14 +02:00
/** @brief Using array index before bounds check */
void arrayIndexThenCheck ( ) ;
2010-04-10 21:12:00 +02:00
/** @brief %Check for buffer overruns by inspecting execution paths */
void executionPaths ( ) ;
2013-03-19 08:22:48 +01:00
/** @brief %Check using POSIX write function and writing outside buffer size */
void writeOutsideBufferSize ( ) ;
2010-03-13 21:42:59 +01:00
/**
* @ brief Get minimum length of format string result
* @ param input_string format string
* @ param parameters given parameters to sprintf
* @ return minimum length of resulting string
*/
2010-12-31 09:30:56 +01:00
static MathLib : : bigint countSprintfLength ( const std : : string & input_string , const std : : list < const Token * > & parameters ) ;
2009-09-25 18:23:44 +02:00
2009-10-07 14:37:20 +02:00
/**
2010-03-13 21:42:59 +01:00
* @ brief % Check code that matches : " sprintf ( %varid% , %str% [,)] " when varid is not 0 ,
2009-10-07 14:37:20 +02:00
* and report found errors .
* @ param tok The " sprintf " token .
* @ param size The size of the buffer where sprintf is writing .
*/
2010-12-31 09:30:56 +01:00
void checkSprintfCall ( const Token * tok , const MathLib : : bigint size ) ;
2009-10-07 14:37:20 +02:00
2009-01-31 20:29:27 +01:00
/** Check for buffer overruns - locate struct variables and check them with the .._CheckScope function */
2009-07-05 22:16:43 +02:00
void checkStructVariable ( ) ;
2009-01-31 20:29:27 +01:00
2009-07-05 22:16:43 +02:00
/** Check for buffer overruns - locate global variables and local function variables and check them with the checkScope function */
void checkGlobalAndLocalVariable ( ) ;
2009-01-31 20:29:27 +01:00
2010-05-26 10:56:34 +02:00
/** Check for buffer overruns due to allocating strlen(src) bytes instead of (strlen(src)+1) bytes before copying a string */
void checkBufferAllocatedWithStrlen ( ) ;
2010-06-02 18:09:25 +02:00
2014-07-06 08:41:39 +02:00
/** Check string argument buffer overruns */
void checkStringArgument ( ) ;
2010-06-02 07:41:07 +02:00
/** Check for buffer overruns due to copying command-line args to fixed-sized buffers without bounds checking */
void checkInsecureCmdLineArgs ( ) ;
2010-05-26 10:56:34 +02:00
2010-04-18 11:08:29 +02:00
/** Information about N-dimensional array */
2012-06-10 14:19:09 +02:00
class CPPCHECKLIB ArrayInfo {
2010-04-18 11:08:29 +02:00
private :
/** number of elements of array */
2010-12-31 09:30:56 +01:00
std : : vector < MathLib : : bigint > _num ;
2010-04-18 11:08:29 +02:00
2012-05-14 20:46:23 +02:00
/** full name of variable as pattern */
std : : string _varname ;
2010-04-18 11:08:29 +02:00
/** size of each element in array */
2010-12-31 09:30:56 +01:00
MathLib : : bigint _element_size ;
2010-04-18 11:08:29 +02:00
2013-07-20 12:31:04 +02:00
/** declaration id */
unsigned int _declarationId ;
2010-04-18 19:46:45 +02:00
2010-04-18 11:08:29 +02:00
public :
ArrayInfo ( ) ;
2013-07-20 12:31:04 +02:00
ArrayInfo ( const Variable * var , const Tokenizer * tokenizer , const unsigned int forcedeclid = 0 ) ;
2010-04-18 11:08:29 +02:00
2010-04-21 18:33:21 +02:00
/**
* Create array info with specified data
* The intention is that this is only a temporary solution . . all
* checking should be based on ArrayInfo from the start and then
* this will not be needed as the declare can be used instead .
*/
2010-12-31 09:30:56 +01:00
ArrayInfo ( unsigned int id , const std : : string & name , MathLib : : bigint size1 , MathLib : : bigint n ) ;
2010-04-21 18:33:21 +02:00
2010-04-24 21:48:58 +02:00
/** Create a copy ArrayInfo where the number of elements have been limited by a value */
2010-11-21 11:48:27 +01:00
ArrayInfo limit ( MathLib : : bigint value ) const ;
2010-04-24 21:48:58 +02:00
2011-06-23 02:35:58 +02:00
/** array sizes */
2014-11-20 14:20:09 +01:00
const std : : vector < MathLib : : bigint > & num ( ) const {
2011-06-23 02:35:58 +02:00
return _num ;
}
2010-04-18 11:08:29 +02:00
/** array size */
2014-11-20 14:20:09 +01:00
MathLib : : bigint num ( std : : size_t index ) const {
2011-06-23 02:35:58 +02:00
return _num [ index ] ;
}
2014-11-20 14:20:09 +01:00
void num ( std : : size_t index , MathLib : : bigint number ) {
2011-09-10 16:14:32 +02:00
_num [ index ] = number ;
}
2010-04-18 11:08:29 +02:00
2010-04-18 20:18:25 +02:00
/** size of each element */
2014-11-20 14:20:09 +01:00
MathLib : : bigint element_size ( ) const {
2011-06-23 02:35:58 +02:00
return _element_size ;
}
2010-04-18 11:08:29 +02:00
2010-04-18 19:46:45 +02:00
/** Variable name */
2014-11-20 14:20:09 +01:00
unsigned int declarationId ( ) const {
2013-07-20 12:31:04 +02:00
return _declarationId ;
2011-06-23 02:35:58 +02:00
}
2014-11-20 14:20:09 +01:00
void declarationId ( unsigned int id ) {
2013-07-20 12:31:04 +02:00
_declarationId = id ;
2011-09-10 17:21:52 +02:00
}
2010-04-18 19:46:45 +02:00
2010-04-18 11:08:29 +02:00
/** Variable name */
2014-11-20 14:20:09 +01:00
const std : : string & varname ( ) const {
2011-06-23 02:35:58 +02:00
return _varname ;
}
2014-11-20 14:20:09 +01:00
void varname ( const std : : string & name ) {
2011-09-12 01:21:13 +02:00
_varname = name ;
}
2010-04-18 11:08:29 +02:00
} ;
2010-04-21 18:33:21 +02:00
/** Check for buffer overruns (based on ArrayInfo) */
void checkScope ( const Token * tok , const ArrayInfo & arrayInfo ) ;
2011-09-10 17:21:52 +02:00
/** Check for buffer overruns */
void checkScope ( const Token * tok , const std : : vector < std : : string > & varname , const ArrayInfo & arrayInfo ) ;
2011-10-24 21:22:04 +02:00
/** Check readlink or readlinkat() buffer usage */
2014-01-02 10:46:19 +01:00
void checkReadlinkBufferUsage ( const Token * ftok , const Token * scope_begin , const unsigned int varid , const MathLib : : bigint total_size ) ;
2011-10-24 21:22:04 +02:00
2010-04-21 20:02:58 +02:00
/**
2011-01-22 21:31:26 +01:00
* Helper function for checkFunctionCall - check a function parameter
2010-04-21 20:02:58 +02:00
* \ param tok token for the function name
* \ param par on what parameter is the array used
* \ param arrayInfo the array information
2011-12-11 08:16:58 +01:00
* \ param callstack call stack . This is used to prevent recursion and to provide better error messages . Pass a empty list from checkScope etc .
2010-04-21 20:02:58 +02:00
*/
2014-06-23 19:06:31 +02:00
void checkFunctionParameter ( const Token & tok , const unsigned int par , const ArrayInfo & arrayInfo , const std : : list < const Token * > & callstack ) ;
2011-01-22 21:31:26 +01:00
/**
* Helper function that checks if the array is used and if so calls the checkFunctionCall
* @ param tok token that matches " %var% ( "
* @ param arrayInfo the array information
2011-12-11 08:16:58 +01:00
* \ param callstack call stack . This is used to prevent recursion and to provide better error messages . Pass a empty list from checkScope etc .
2011-01-22 21:31:26 +01:00
*/
2011-12-11 08:16:58 +01:00
void checkFunctionCall ( const Token * tok , const ArrayInfo & arrayInfo , std : : list < const Token * > callstack ) ;
2010-04-18 11:08:29 +02:00
2011-08-24 13:11:39 +02:00
void arrayIndexOutOfBoundsError ( const Token * tok , const ArrayInfo & arrayInfo , const std : : vector < MathLib : : bigint > & index ) ;
2014-01-22 21:25:37 +01:00
void arrayIndexOutOfBoundsError ( const Token * tok , const ArrayInfo & arrayInfo , const std : : vector < ValueFlow : : Value > & index ) ;
2013-03-14 06:34:12 +01:00
2014-11-15 10:43:49 +01:00
/* data for multifile checking */
class MyFileInfo : public Check : : FileInfo {
public :
struct ArrayUsage {
MathLib : : bigint index ;
std : : string fileName ;
unsigned int linenr ;
} ;
/* key:arrayName */
std : : map < std : : string , struct ArrayUsage > arrayUsage ;
/* key:arrayName, data:arraySize */
std : : map < std : : string , MathLib : : bigint > arraySize ;
} ;
/** @brief Parse current TU and extract file info */
2014-12-02 06:41:18 +01:00
Check : : FileInfo * getFileInfo ( const Tokenizer * tokenizer , const Settings * settings ) const ;
2014-11-15 10:43:49 +01:00
/** @brief Analyse all file infos for all TU */
2014-12-02 06:41:18 +01:00
void analyseWholeProgram ( const std : : list < Check : : FileInfo * > & fileInfo , ErrorLogger & errorLogger ) ;
2014-11-15 10:43:49 +01:00
2012-03-17 21:55:08 +01:00
private :
2013-03-14 06:34:12 +01:00
2013-06-01 14:06:48 +02:00
static bool isArrayOfStruct ( const Token * tok , int & position ) ;
2011-08-24 13:11:39 +02:00
void arrayIndexOutOfBoundsError ( const std : : list < const Token * > & callstack , const ArrayInfo & arrayInfo , const std : : vector < MathLib : : bigint > & index ) ;
2014-06-26 11:44:19 +02:00
void bufferOverrunError ( const Token * tok , const std : : string & varnames = emptyString ) ;
void bufferOverrunError ( const std : : list < const Token * > & callstack , const std : : string & varnames = emptyString ) ;
2011-08-24 13:11:39 +02:00
void strncatUsageError ( const Token * tok ) ;
2014-02-01 22:38:29 +01:00
void negativeMemoryAllocationSizeError ( const Token * tok ) ; // provide a negative value to memory allocation function
2011-10-05 20:17:57 +02:00
void outOfBoundsError ( const Token * tok , const std : : string & what , const bool show_size_info , const MathLib : : bigint & supplied_size , const MathLib : : bigint & actual_size ) ;
2011-08-24 13:11:39 +02:00
void sizeArgumentAsCharError ( const Token * tok ) ;
2011-09-05 21:59:41 +02:00
void terminateStrncpyError ( const Token * tok , const std : : string & varname ) ;
void bufferNotZeroTerminatedError ( const Token * tok , const std : : string & varname , const std : : string & function ) ;
2010-11-21 11:48:27 +01:00
void negativeIndexError ( const Token * tok , MathLib : : bigint index ) ;
2014-04-02 06:49:28 +02:00
void negativeIndexError ( const Token * tok , const ValueFlow : : Value & index ) ;
2010-06-02 07:41:07 +02:00
void cmdLineArgsError ( const Token * tok ) ;
2012-09-15 15:32:00 +02:00
void pointerOutOfBoundsError ( const Token * tok , const std : : string & object ) ; // UB when result of calculation is out of bounds
2011-08-04 11:15:14 +02:00
void arrayIndexThenCheckError ( const Token * tok , const std : : string & indexName ) ;
2011-08-21 21:18:41 +02:00
void possibleBufferOverrunError ( const Token * tok , const std : : string & src , const std : : string & dst , bool cat ) ;
2011-10-24 21:22:04 +02:00
void possibleReadlinkBufferOverrunError ( const Token * tok , const std : : string & funcname , const std : : string & varname ) ;
2012-12-22 09:23:34 +01:00
void argumentSizeError ( const Token * tok , const std : : string & functionName , const std : : string & varname ) ;
2013-03-19 08:22:48 +01:00
void writeOutsideBufferSizeError ( const Token * tok , const std : : size_t stringLength , const MathLib : : bigint writeLength , const std : : string & functionName ) ;
2009-03-22 08:20:15 +01:00
2014-03-29 20:20:22 +01:00
void valueFlowCheckArrayIndex ( const Token * const tok , const ArrayInfo & arrayInfo ) ;
2012-03-17 21:55:08 +01:00
public :
2014-11-20 14:20:09 +01:00
void getErrorMessages ( ErrorLogger * errorLogger , const Settings * settings ) const {
2010-12-29 12:43:29 +01:00
CheckBufferOverrun c ( 0 , settings , errorLogger ) ;
2011-09-11 15:54:26 +02:00
std : : vector < MathLib : : bigint > indexes ;
indexes . push_back ( 2 ) ;
c . arrayIndexOutOfBoundsError ( 0 , ArrayInfo ( 0 , " array " , 1 , 2 ) , indexes ) ;
2011-08-24 13:11:39 +02:00
c . bufferOverrunError ( 0 , std : : string ( " buffer " ) ) ;
c . strncatUsageError ( 0 ) ;
2011-10-05 20:17:57 +02:00
c . outOfBoundsError ( 0 , " index " , true , 2 , 1 ) ;
2011-08-24 13:11:39 +02:00
c . sizeArgumentAsCharError ( 0 ) ;
2011-09-05 21:59:41 +02:00
c . terminateStrncpyError ( 0 , " buffer " ) ;
c . bufferNotZeroTerminatedError ( 0 , " buffer " , " strncpy " ) ;
2010-12-29 12:43:29 +01:00
c . negativeIndexError ( 0 , - 1 ) ;
c . cmdLineArgsError ( 0 ) ;
2011-08-24 13:11:39 +02:00
c . pointerOutOfBoundsError ( 0 , " array " ) ;
2011-08-04 11:15:14 +02:00
c . arrayIndexThenCheckError ( 0 , " index " ) ;
2011-08-21 21:18:41 +02:00
c . possibleBufferOverrunError ( 0 , " source " , " destination " , false ) ;
2011-10-24 21:22:04 +02:00
c . possibleReadlinkBufferOverrunError ( 0 , " readlink " , " buffer " ) ;
2012-12-22 09:23:34 +01:00
c . argumentSizeError ( 0 , " function " , " array " ) ;
2013-03-19 08:22:48 +01:00
c . writeOutsideBufferSizeError ( 0 , 2 , 3 , " write " ) ;
2014-02-01 22:38:29 +01:00
c . negativeMemoryAllocationSizeError ( 0 ) ;
2014-06-28 10:09:53 +02:00
c . reportError ( nullptr , Severity : : warning , " arrayIndexOutOfBoundsCond " , " Array 'x[10]' accessed at index 20, which is out of bounds. Otherwise condition 'y==20' is redundant. " ) ;
2009-03-22 08:20:15 +01:00
}
2012-03-17 21:55:08 +01:00
private :
2009-06-12 12:19:37 +02:00
2014-11-20 14:20:09 +01:00
static std : : string myName ( ) {
2009-06-12 15:20:08 +02:00
return " Bounds checking " ;
}
2014-11-20 14:20:09 +01:00
std : : string classInfo ( ) const {
2014-05-22 09:13:29 +02:00
return " Out of bounds checking: \n "
2014-09-30 14:56:12 +02:00
" - Array index out of bounds detection by value flow analysis \n "
" - Dangerous usage of strncat() \n "
" - char constant passed as size to function like memset() \n "
" - strncpy() leaving string unterminated \n "
" - Accessing array with negative index \n "
" - Unsafe usage of main(argv, argc) arguments \n "
" - Accessing array with index variable before checking its value \n "
" - Check for large enough arrays being passed to functions \n "
" - Writing beyond bounds of a buffer \n "
" - Allocating memory with a negative size \n " ;
2009-06-12 12:19:37 +02:00
}
2009-01-31 20:29:27 +01:00
} ;
2009-07-17 10:49:01 +02:00
/// @}
2009-01-31 20:29:27 +01:00
//---------------------------------------------------------------------------
2013-09-04 20:59:49 +02:00
# endif // checkbufferoverrunH