2323#include " checkbufferoverrun.h"
2424
2525#include " astutils.h"
26+ #include " checkimpl.h"
2627#include " errorlogger.h"
2728#include " library.h"
2829#include " mathlib.h"
@@ -63,6 +64,46 @@ static const CWE CWE_BUFFER_OVERRUN(788U); // Access of Memory Location After
6364
6465// ---------------------------------------------------------------------------
6566
67+ class CheckBufferOverrunImpl : public CheckImpl
68+ {
69+ public:
70+ /* * This constructor is used when running checks. */
71+ CheckBufferOverrunImpl (const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
72+ : CheckImpl(tokenizer, settings, errorLogger) {}
73+
74+ void arrayIndex ();
75+ void arrayIndexError (const Token* tok,
76+ const std::vector<Dimension>& dimensions,
77+ const std::vector<ValueFlow::Value>& indexes);
78+ void negativeIndexError (const Token* tok,
79+ const std::vector<Dimension>& dimensions,
80+ const std::vector<ValueFlow::Value>& indexes);
81+
82+ void pointerArithmetic ();
83+ void pointerArithmeticError (const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue);
84+
85+ void bufferOverflow ();
86+ void bufferOverflowError (const Token *tok, const ValueFlow::Value *value, Certainty certainty);
87+
88+ void arrayIndexThenCheck ();
89+ void arrayIndexThenCheckError (const Token *tok, const std::string &indexName);
90+
91+ void stringNotZeroTerminated ();
92+ void terminateStrncpyError (const Token *tok, const std::string &varname);
93+
94+ void argumentSize ();
95+ void argumentSizeError (const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string ¶mExpression, const Variable *paramVar, const Variable *functionArg);
96+
97+ void negativeArraySize ();
98+ void negativeArraySizeError (const Token* tok);
99+ void negativeMemoryAllocationSizeError (const Token* tok, const ValueFlow::Value* value); // provide a negative value to memory allocation function
100+
101+ void objectIndex ();
102+ void objectIndexError (const Token *tok, const ValueFlow::Value *v, bool known);
103+
104+ ValueFlow::Value getBufferSize (const Token *bufTok) const ;
105+ };
106+
66107static const ValueFlow::Value *getBufferSizeValue (const Token *tok)
67108{
68109 const std::list<ValueFlow::Value> &tokenValues = tok->values ();
@@ -278,7 +319,7 @@ static std::vector<ValueFlow::Value> getOverrunIndexValues(const Token* tok,
278319 return {};
279320}
280321
281- void CheckBufferOverrun ::arrayIndex ()
322+ void CheckBufferOverrunImpl ::arrayIndex ()
282323{
283324 for (const Token *tok = mTokenizer ->tokens (); tok; tok = tok->next ()) {
284325 if (tok->str () != " [" )
@@ -397,7 +438,7 @@ static std::string arrayIndexMessage(const Token* tok,
397438 return errmsg.str ();
398439}
399440
400- void CheckBufferOverrun ::arrayIndexError (const Token* tok,
441+ void CheckBufferOverrunImpl ::arrayIndexError (const Token* tok,
401442 const std::vector<Dimension>& dimensions,
402443 const std::vector<ValueFlow::Value>& indexes)
403444{
@@ -426,7 +467,7 @@ void CheckBufferOverrun::arrayIndexError(const Token* tok,
426467 index->isInconclusive () ? Certainty::inconclusive : Certainty::normal);
427468}
428469
429- void CheckBufferOverrun ::negativeIndexError (const Token* tok,
470+ void CheckBufferOverrunImpl ::negativeIndexError (const Token* tok,
430471 const std::vector<Dimension>& dimensions,
431472 const std::vector<ValueFlow::Value>& indexes)
432473{
@@ -456,7 +497,7 @@ void CheckBufferOverrun::negativeIndexError(const Token* tok,
456497
457498// ---------------------------------------------------------------------------
458499
459- void CheckBufferOverrun ::pointerArithmetic ()
500+ void CheckBufferOverrunImpl ::pointerArithmetic ()
460501{
461502 if (!mSettings ->severity .isEnabled (Severity::portability))
462503 return ;
@@ -518,7 +559,7 @@ void CheckBufferOverrun::pointerArithmetic()
518559 }
519560}
520561
521- void CheckBufferOverrun ::pointerArithmeticError (const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue)
562+ void CheckBufferOverrunImpl ::pointerArithmeticError (const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue)
522563{
523564 if (!tok) {
524565 reportError (tok, Severity::portability, " pointerOutOfBounds" , " Pointer arithmetic overflow." , CWE_POINTER_ARITHMETIC_OVERFLOW, Certainty::normal);
@@ -542,7 +583,7 @@ void CheckBufferOverrun::pointerArithmeticError(const Token *tok, const Token *i
542583
543584// ---------------------------------------------------------------------------
544585
545- ValueFlow::Value CheckBufferOverrun ::getBufferSize (const Token *bufTok) const
586+ ValueFlow::Value CheckBufferOverrunImpl ::getBufferSize (const Token *bufTok) const
546587{
547588 if (!bufTok->valueType ())
548589 return ValueFlow::Value (-1 );
@@ -624,7 +665,7 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
624665}
625666
626667
627- void CheckBufferOverrun ::bufferOverflow ()
668+ void CheckBufferOverrunImpl ::bufferOverflow ()
628669{
629670 const SymbolDatabase *symbolDatabase = mTokenizer ->getSymbolDatabase ();
630671 for (const Scope * scope : symbolDatabase->functionScopes ) {
@@ -679,14 +720,14 @@ void CheckBufferOverrun::bufferOverflow()
679720 }
680721}
681722
682- void CheckBufferOverrun ::bufferOverflowError (const Token *tok, const ValueFlow::Value *value, Certainty certainty)
723+ void CheckBufferOverrunImpl ::bufferOverflowError (const Token *tok, const ValueFlow::Value *value, Certainty certainty)
683724{
684725 reportError (getErrorPath (tok, value, " Buffer overrun" ), Severity::error, " bufferAccessOutOfBounds" , " Buffer is accessed out of bounds: " + (tok ? tok->expressionString () : " buf" ), CWE_BUFFER_OVERRUN, certainty);
685726}
686727
687728// ---------------------------------------------------------------------------
688729
689- void CheckBufferOverrun ::arrayIndexThenCheck ()
730+ void CheckBufferOverrunImpl ::arrayIndexThenCheck ()
690731{
691732 if (!mSettings ->severity .isEnabled (Severity::portability))
692733 return ;
@@ -728,7 +769,7 @@ void CheckBufferOverrun::arrayIndexThenCheck()
728769 }
729770}
730771
731- void CheckBufferOverrun ::arrayIndexThenCheckError (const Token *tok, const std::string &indexName)
772+ void CheckBufferOverrunImpl ::arrayIndexThenCheckError (const Token *tok, const std::string &indexName)
732773{
733774 reportError (tok, Severity::style, " arrayIndexThenCheck" ,
734775 " $symbol:" + indexName + " \n "
@@ -741,7 +782,7 @@ void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::s
741782
742783// ---------------------------------------------------------------------------
743784
744- void CheckBufferOverrun ::stringNotZeroTerminated ()
785+ void CheckBufferOverrunImpl ::stringNotZeroTerminated ()
745786{
746787 // this is currently 'inconclusive'. See TestBufferOverrun::terminateStrncpy3
747788 if (!mSettings ->severity .isEnabled (Severity::warning) || !mSettings ->certainty .isEnabled (Certainty::inconclusive))
@@ -791,7 +832,7 @@ void CheckBufferOverrun::stringNotZeroTerminated()
791832 }
792833}
793834
794- void CheckBufferOverrun ::terminateStrncpyError (const Token *tok, const std::string &varname)
835+ void CheckBufferOverrunImpl ::terminateStrncpyError (const Token *tok, const std::string &varname)
795836{
796837 const std::string shortMessage = " The buffer '$symbol' may not be null-terminated after the call to strncpy()." ;
797838 reportError (tok, Severity::warning, " terminateStrncpy" ,
@@ -804,7 +845,7 @@ void CheckBufferOverrun::terminateStrncpyError(const Token *tok, const std::stri
804845}
805846// ---------------------------------------------------------------------------
806847
807- void CheckBufferOverrun ::argumentSize ()
848+ void CheckBufferOverrunImpl ::argumentSize ()
808849{
809850 // Check '%type% x[10]' arguments
810851 if (!mSettings ->severity .isEnabled (Severity::warning))
@@ -850,7 +891,7 @@ void CheckBufferOverrun::argumentSize()
850891 }
851892}
852893
853- void CheckBufferOverrun ::argumentSizeError (const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string ¶mExpression, const Variable *paramVar, const Variable *functionArg)
894+ void CheckBufferOverrunImpl ::argumentSizeError (const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string ¶mExpression, const Variable *paramVar, const Variable *functionArg)
854895{
855896 const std::string strParamNum = std::to_string (paramIndex + 1 ) + getOrdinalText (paramIndex + 1 );
856897 ErrorPath errorPath;
@@ -917,7 +958,7 @@ bool CheckBufferOverrun::isCtuUnsafePointerArith(const Check *check, const Token
917958/* * @brief Parse current TU and extract file info */
918959Check::FileInfo *CheckBufferOverrun::getFileInfo (const Tokenizer *tokenizer, const Settings *settings) const
919960{
920- CheckBufferOverrun checkBufferOverrun (tokenizer, settings, nullptr );
961+ CheckBufferOverrunImpl checkBufferOverrun (tokenizer, settings, nullptr );
921962 MyFileInfo *fileInfo = new MyFileInfo;
922963 fileInfo->unsafeArrayIndex = CTU::getUnsafeUsage (tokenizer, settings, &checkBufferOverrun, isCtuUnsafeArrayIndex);
923964 fileInfo->unsafePointerArith = CTU::getUnsafeUsage (tokenizer, settings, &checkBufferOverrun, isCtuUnsafePointerArith);
@@ -1013,7 +1054,7 @@ bool CheckBufferOverrun::analyseWholeProgram1(const std::map<std::string, std::l
10131054 return true ;
10141055}
10151056
1016- void CheckBufferOverrun ::objectIndex ()
1057+ void CheckBufferOverrunImpl ::objectIndex ()
10171058{
10181059 const SymbolDatabase *symbolDatabase = mTokenizer ->getSymbolDatabase ();
10191060 for (const Scope *functionScope : symbolDatabase->functionScopes ) {
@@ -1086,7 +1127,7 @@ void CheckBufferOverrun::objectIndex()
10861127 }
10871128}
10881129
1089- void CheckBufferOverrun ::objectIndexError (const Token *tok, const ValueFlow::Value *v, bool known)
1130+ void CheckBufferOverrunImpl ::objectIndexError (const Token *tok, const ValueFlow::Value *v, bool known)
10901131{
10911132 ErrorPath errorPath;
10921133 std::string name;
@@ -1120,7 +1161,7 @@ static bool isVLAIndex(const Token* tok)
11201161 return isVLAIndex (tok->astOperand1 ()) || isVLAIndex (tok->astOperand2 ());
11211162}
11221163
1123- void CheckBufferOverrun ::negativeArraySize ()
1164+ void CheckBufferOverrunImpl ::negativeArraySize ()
11241165{
11251166 const SymbolDatabase* symbolDatabase = mTokenizer ->getSymbolDatabase ();
11261167 for (const Variable* var : symbolDatabase->variableList ()) {
@@ -1149,7 +1190,7 @@ void CheckBufferOverrun::negativeArraySize()
11491190 }
11501191}
11511192
1152- void CheckBufferOverrun ::negativeArraySizeError (const Token* tok)
1193+ void CheckBufferOverrunImpl ::negativeArraySizeError (const Token* tok)
11531194{
11541195 const std::string arrayName = tok ? tok->expressionString () : std::string ();
11551196 const std::string line1 = arrayName.empty () ? std::string () : (" $symbol:" + arrayName + ' \n ' );
@@ -1158,11 +1199,38 @@ void CheckBufferOverrun::negativeArraySizeError(const Token* tok)
11581199 " Declaration of array '" + arrayName + " ' with negative size is undefined behaviour" , CWE758, Certainty::normal);
11591200}
11601201
1161- void CheckBufferOverrun ::negativeMemoryAllocationSizeError (const Token* tok, const ValueFlow::Value* value)
1202+ void CheckBufferOverrunImpl ::negativeMemoryAllocationSizeError (const Token* tok, const ValueFlow::Value* value)
11621203{
11631204 const std::string msg = " Memory allocation size is negative." ;
11641205 const ErrorPath errorPath = getErrorPath (tok, value, msg);
11651206 const bool inconclusive = value != nullptr && !value->isKnown ();
11661207 reportError (errorPath, inconclusive ? Severity::warning : Severity::error, " negativeMemoryAllocationSize" ,
11671208 msg, CWE131, inconclusive ? Certainty::inconclusive : Certainty::normal);
11681209}
1210+
1211+ void CheckBufferOverrun::runChecks (const Tokenizer &tokenizer, ErrorLogger *errorLogger)
1212+ {
1213+ CheckBufferOverrunImpl checkBufferOverrun (&tokenizer, tokenizer.getSettings (), errorLogger);
1214+ checkBufferOverrun.arrayIndex ();
1215+ checkBufferOverrun.pointerArithmetic ();
1216+ checkBufferOverrun.bufferOverflow ();
1217+ checkBufferOverrun.arrayIndexThenCheck ();
1218+ checkBufferOverrun.stringNotZeroTerminated ();
1219+ checkBufferOverrun.objectIndex ();
1220+ checkBufferOverrun.argumentSize ();
1221+ checkBufferOverrun.negativeArraySize ();
1222+ }
1223+
1224+ void CheckBufferOverrun::getErrorMessages (ErrorLogger *errorLogger, const Settings *settings) const
1225+ {
1226+ CheckBufferOverrunImpl c (nullptr , settings, errorLogger);
1227+ c.arrayIndexError (nullptr , std::vector<Dimension>(), std::vector<ValueFlow::Value>());
1228+ c.pointerArithmeticError (nullptr , nullptr , nullptr );
1229+ c.negativeIndexError (nullptr , std::vector<Dimension>(), std::vector<ValueFlow::Value>());
1230+ c.arrayIndexThenCheckError (nullptr , " i" );
1231+ c.bufferOverflowError (nullptr , nullptr , Certainty::normal);
1232+ c.objectIndexError (nullptr , nullptr , true );
1233+ c.argumentSizeError (nullptr , " function" , 1 , " buffer" , nullptr , nullptr );
1234+ c.negativeMemoryAllocationSizeError (nullptr , nullptr );
1235+ c.negativeArraySizeError (nullptr );
1236+ }
0 commit comments