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());
}
//---------------------------------------------------------------------------
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..
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)
{
@ -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);
}
//---------------------------------------------------------------------------
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.arrayIndex();
checkBufferOverrun.bufferOverflow();
checkBufferOverrun.arrayIndexThenCheck();
}
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
@ -89,6 +90,7 @@ public:
CheckBufferOverrun c(nullptr, settings, errorLogger);
c.arrayIndexError(nullptr, nullptr, nullptr);
c.negativeIndexError(nullptr, nullptr, nullptr);
c.arrayIndexThenCheckError(nullptr, "i");
}
private:
@ -100,6 +102,9 @@ private:
void bufferOverflow();
void bufferOverflowError(const Token *tok);
void arrayIndexThenCheck();
void arrayIndexThenCheckError(const Token *tok, const std::string &indexName);
size_t getBufferSize(const Token *bufTok) const;
static std::string myName() {
@ -110,7 +115,8 @@ private:
return "Out of bounds checking:\n"
"- Array index out of bounds\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);
// Access array and then check if the used index is within bounds
// TODO TEST_CASE(arrayIndexThenCheck);
TEST_CASE(arrayIndexThenCheck);
// TODO TEST_CASE(bufferNotZeroTerminated);