2009-01-31 20:29:27 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 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"
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
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
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
// CWE ids used
static const struct CWE CWE119 ( 119U ) ; // Improper Restriction of Operations within the Bounds of a Memory Buffer
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 */
2016-07-08 20:53:08 +02:00
CheckBufferOverrun ( ) : Check ( myName ( ) ) , symbolDatabase ( nullptr ) {
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 )
2016-07-08 20:53:08 +02:00
: Check ( myName ( ) , tokenizer , settings , errorLogger )
, symbolDatabase ( tokenizer ? tokenizer - > getSymbolDatabase ( ) : nullptr ) {
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 ) ;
2016-07-07 19:38:15 +02:00
checkBufferOverrun . checkGlobalAndLocalVariable ( ) ;
2016-07-10 22:24:28 +02:00
if ( tokenizer & & tokenizer - > isMaxTime ( ) )
2016-07-07 19:38:15 +02:00
return ;
checkBufferOverrun . checkStructVariable ( ) ;
checkBufferOverrun . checkBufferAllocatedWithStrlen ( ) ;
checkBufferOverrun . checkInsecureCmdLineArgs ( ) ;
2009-10-13 21:39:51 +02:00
checkBufferOverrun . bufferOverrun ( ) ;
2011-08-04 11:15:14 +02:00
checkBufferOverrun . arrayIndexThenCheck ( ) ;
2015-05-03 15:00:47 +02:00
checkBufferOverrun . negativeArraySize ( ) ;
2009-03-20 17:35:53 +01:00
}
2009-01-31 20:29:27 +01:00
2016-07-07 19:38:15 +02:00
void runChecks ( const Tokenizer * tokenizer , const Settings * settings , ErrorLogger * errorLogger ) {
CheckBufferOverrun checkBufferOverrun ( tokenizer , settings , errorLogger ) ;
checkBufferOverrun . checkStringArgument ( ) ;
}
2010-03-13 21:42:59 +01:00
2016-07-07 19:38:15 +02:00
/** @brief %Check for buffer overruns (single pass, use ast and valueflow) */
void bufferOverrun ( ) ;
2014-06-26 17:36:20 +02:00
2011-08-04 11:15:14 +02:00
/** @brief Using array index before bounds check */
void arrayIndexThenCheck ( ) ;
2015-05-03 15:00:47 +02:00
/** @brief negative size for array */
void negativeArraySize ( ) ;
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
*/
2015-02-18 20:56:44 +01:00
static MathLib : : biguint countSprintfLength ( const std : : string & input_string , const std : : list < const Token * > & parameters ) ;
2009-09-25 18:23:44 +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 ( ) ;
2016-07-08 20:53:08 +02:00
ArrayInfo ( const Variable * var , const SymbolDatabase * symbolDatabase , 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 ;
}
2015-11-08 12:39:08 +01:00
MathLib : : bigint numberOfElements ( ) const ;
MathLib : : bigint totalIndex ( const std : : vector < ValueFlow : : Value > & indexes ) const ;
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 ) ;
2016-05-25 14:41:26 +02:00
void checkScope ( const Token * tok , std : : map < unsigned int , ArrayInfo > arrayInfo ) ;
void checkScope_inner ( const Token * tok , const ArrayInfo & arrayInfo ) ;
2010-04-21 18:33:21 +02:00
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 ) ;
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
2016-01-15 15:20:40 +01:00
* \ param paramIndex on what parameter is the array used
2010-04-21 20:02:58 +02:00
* \ 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
*/
2016-01-15 15:20:40 +01:00
void checkFunctionParameter ( const Token & tok , const unsigned int paramIndex , 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
2015-01-31 10:50:39 +01:00
* @ param tok token that matches " %name% ( "
2011-01-22 21:31:26 +01:00
* @ 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 :
2016-10-29 12:18:11 +02:00
std : : string toString ( ) const ;
2014-11-15 10:43:49 +01:00
struct ArrayUsage {
MathLib : : bigint index ;
std : : string fileName ;
unsigned int linenr ;
} ;
/* key:arrayName */
2015-08-15 19:16:48 +02:00
std : : map < std : : string , ArrayUsage > arrayUsage ;
2014-11-15 10:43:49 +01:00
/* 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 */
2015-06-28 17:54:48 +02:00
void analyseWholeProgram ( const std : : list < Check : : FileInfo * > & fileInfo , const Settings & settings , ErrorLogger & errorLogger ) ;
2014-11-15 10:43:49 +01:00
2016-07-08 20:53:08 +02:00
/**
* Calculates sizeof value for given type .
* @ param type Token which will contain e . g . " int " , " * " , or string .
* @ return sizeof for given type , or 0 if it can ' t be calculated .
*/
unsigned int sizeOfType ( const Token * type ) const ;
2012-03-17 21:55:08 +01:00
private :
2016-07-08 20:53:08 +02:00
const SymbolDatabase * symbolDatabase ;
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
2015-05-03 15:00:47 +02:00
void negativeArraySizeError ( const Token * tok ) ;
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 ) ;
2014-12-25 10:05:55 +01:00
void pointerOutOfBoundsError ( const Token * tok , const Token * index = nullptr , const MathLib : : bigint indexvalue = 0 ) ;
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 ) ;
2012-12-22 09:23:34 +01:00
void argumentSizeError ( const Token * tok , const std : : string & functionName , const std : : string & varname ) ;
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 {
2016-05-07 16:30:54 +02:00
CheckBufferOverrun c ( nullptr , settings , errorLogger ) ;
2015-08-15 19:16:48 +02:00
const std : : vector < MathLib : : bigint > indexes ( 2 , 1 ) ;
2016-05-07 16:30:54 +02:00
c . arrayIndexOutOfBoundsError ( nullptr , ArrayInfo ( 0 , " array " , 1 , 2 ) , indexes ) ;
c . bufferOverrunError ( nullptr , std : : string ( " buffer " ) ) ;
c . strncatUsageError ( nullptr ) ;
c . outOfBoundsError ( nullptr , " index " , true , 2 , 1 ) ;
c . sizeArgumentAsCharError ( nullptr ) ;
c . terminateStrncpyError ( nullptr , " buffer " ) ;
c . bufferNotZeroTerminatedError ( nullptr , " buffer " , " strncpy " ) ;
c . negativeIndexError ( nullptr , - 1 ) ;
c . cmdLineArgsError ( nullptr ) ;
2014-12-25 10:05:55 +01:00
c . pointerOutOfBoundsError ( nullptr , nullptr , 0 ) ;
2016-05-07 16:30:54 +02:00
c . arrayIndexThenCheckError ( nullptr , " index " ) ;
c . possibleBufferOverrunError ( nullptr , " source " , " destination " , false ) ;
c . argumentSizeError ( nullptr , " function " , " array " ) ;
c . negativeMemoryAllocationSizeError ( nullptr ) ;
c . negativeArraySizeError ( nullptr ) ;
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01: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. " , CWE119 , false ) ;
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 "
" - 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