Add CheckBufferOverrun::arrayIndexThenCheck
This commit is contained in:
parent
a933261e14
commit
bd048085bd
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue