Add CheckBufferOverrun::arrayIndexThenCheck

This commit is contained in:
Daniel Marjamäki 2019-03-11 19:20:06 +01:00
parent a933261e14
commit bd048085bd
3 changed files with 65 additions and 2 deletions

View File

@ -278,6 +278,7 @@ void CheckBufferOverrun::negativeIndexError(const Token *tok, const Variable *va
negativeValue->isInconclusive()); negativeValue->isInconclusive());
} }
//---------------------------------------------------------------------------
size_t CheckBufferOverrun::getBufferSize(const Token *bufTok) const size_t CheckBufferOverrun::getBufferSize(const Token *bufTok) const
{ {
@ -318,6 +319,7 @@ size_t CheckBufferOverrun::getBufferSize(const Token *bufTok) const
// TODO: For pointers get pointer value.. // TODO: For pointers get pointer value..
return 0; return 0;
} }
//---------------------------------------------------------------------------
static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::MinSize &minsize, const std::vector<const Token *> &args, const MathLib::bigint bufferSize, const Settings *settings) static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::MinSize &minsize, const std::vector<const Token *> &args, const MathLib::bigint bufferSize, const Settings *settings)
{ {
@ -398,3 +400,58 @@ void CheckBufferOverrun::bufferOverflowError(const Token *tok)
{ {
reportError(tok, Severity::error, "bufferAccessOutOfBounds", "Buffer is accessed out of bounds: " + (tok ? tok->expressionString() : "buf"), CWE788, false); reportError(tok, Severity::error, "bufferAccessOutOfBounds", "Buffer is accessed out of bounds: " + (tok ? tok->expressionString() : "buf"), CWE788, false);
} }
//---------------------------------------------------------------------------
void CheckBufferOverrun::arrayIndexThenCheck()
{
if (!mSettings->isEnabled(Settings::PORTABILITY))
return;
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
for (const Scope * const scope : symbolDatabase->functionScopes) {
for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) {
tok = tok->linkAt(1);
continue;
}
if (Token::Match(tok, "%name% [ %var% ]")) {
tok = tok->next();
const unsigned int indexID = tok->next()->varId();
const std::string& indexName(tok->strAt(1));
// Iterate AST upwards
const Token* tok2 = tok;
const Token* tok3 = tok2;
while (tok2->astParent() && tok2->tokType() != Token::eLogicalOp) {
tok3 = tok2;
tok2 = tok2->astParent();
}
// Ensure that we ended at a logical operator and that we came from its left side
if (tok2->tokType() != Token::eLogicalOp || tok2->astOperand1() != tok3)
continue;
// check if array index is ok
// statement can be closed in parentheses, so "(| " is using
if (Token::Match(tok2, "&& (| %varid% <|<=", indexID))
arrayIndexThenCheckError(tok, indexName);
else if (Token::Match(tok2, "&& (| %any% >|>= %varid% !!+", indexID))
arrayIndexThenCheckError(tok, indexName);
}
}
}
}
void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::string &indexName)
{
reportError(tok, Severity::style, "arrayIndexThenCheck",
"$symbol:" + indexName + "\n"
"Array index '$symbol' is used before limits check.\n"
"Defensive programming: The variable '$symbol' is used as an array index before it "
"is checked that is within limits. This can mean that the array might be accessed out of bounds. "
"Reorder conditions such as '(a[i] && i < 10)' to '(i < 10 && a[i])'. That way the array will "
"not be accessed if the index is out of limits.", CWE398, false);
}

View File

@ -77,6 +77,7 @@ public:
CheckBufferOverrun checkBufferOverrun(tokenizer, settings, errorLogger); CheckBufferOverrun checkBufferOverrun(tokenizer, settings, errorLogger);
checkBufferOverrun.arrayIndex(); checkBufferOverrun.arrayIndex();
checkBufferOverrun.bufferOverflow(); checkBufferOverrun.bufferOverflow();
checkBufferOverrun.arrayIndexThenCheck();
} }
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE { void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
@ -89,6 +90,7 @@ public:
CheckBufferOverrun c(nullptr, settings, errorLogger); CheckBufferOverrun c(nullptr, settings, errorLogger);
c.arrayIndexError(nullptr, nullptr, nullptr); c.arrayIndexError(nullptr, nullptr, nullptr);
c.negativeIndexError(nullptr, nullptr, nullptr); c.negativeIndexError(nullptr, nullptr, nullptr);
c.arrayIndexThenCheckError(nullptr, "i");
} }
private: private:
@ -100,6 +102,9 @@ private:
void bufferOverflow(); void bufferOverflow();
void bufferOverflowError(const Token *tok); void bufferOverflowError(const Token *tok);
void arrayIndexThenCheck();
void arrayIndexThenCheckError(const Token *tok, const std::string &indexName);
size_t getBufferSize(const Token *bufTok) const; size_t getBufferSize(const Token *bufTok) const;
static std::string myName() { static std::string myName() {
@ -110,7 +115,8 @@ private:
return "Out of bounds checking:\n" return "Out of bounds checking:\n"
"- Array index out of bounds\n" "- Array index out of bounds\n"
"- Buffer overflow\n" "- Buffer overflow\n"
"- Dangerous usage of strncat()\n"; "- Dangerous usage of strncat()\n"
"- Using array index before checking it\n";
} }
}; };
/// @} /// @}

View File

@ -239,7 +239,7 @@ private:
TEST_CASE(getErrorMessages); TEST_CASE(getErrorMessages);
// Access array and then check if the used index is within bounds // Access array and then check if the used index is within bounds
// TODO TEST_CASE(arrayIndexThenCheck); TEST_CASE(arrayIndexThenCheck);
// TODO TEST_CASE(bufferNotZeroTerminated); // TODO TEST_CASE(bufferNotZeroTerminated);