CheckBufferOverrun: Reimplement CheckBufferOverrun::argumentSize check
This commit is contained in:
parent
0662c94d83
commit
db57efa486
|
@ -52,6 +52,7 @@ namespace {
|
||||||
// CWE ids used:
|
// CWE ids used:
|
||||||
static const CWE CWE131(131U); // Incorrect Calculation of Buffer Size
|
static const CWE CWE131(131U); // Incorrect Calculation of Buffer Size
|
||||||
static const CWE CWE170(170U); // Improper Null Termination
|
static const CWE CWE170(170U); // Improper Null Termination
|
||||||
|
static const CWE CWE_ARGUMENT_SIZE(398U); // Indicator of Poor Code Quality
|
||||||
static const CWE CWE_ARRAY_INDEX_THEN_CHECK(398U); // Indicator of Poor Code Quality
|
static const CWE CWE_ARRAY_INDEX_THEN_CHECK(398U); // Indicator of Poor Code Quality
|
||||||
static const CWE CWE682(682U); // Incorrect Calculation
|
static const CWE CWE682(682U); // Incorrect Calculation
|
||||||
static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
|
static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
|
||||||
|
@ -761,8 +762,61 @@ void CheckBufferOverrun::terminateStrncpyError(const Token *tok, const std::stri
|
||||||
"zero at the end of the buffer. This causes bugs later in the code if the code "
|
"zero at the end of the buffer. This causes bugs later in the code if the code "
|
||||||
"assumes buffer is null-terminated.", CWE170, Certainty::inconclusive);
|
"assumes buffer is null-terminated.", CWE170, Certainty::inconclusive);
|
||||||
}
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CheckBufferOverrun::argumentSize()
|
||||||
|
{
|
||||||
|
// Check '%type% x[10]' arguments
|
||||||
|
if (!mSettings->severity.isEnabled(Severity::warning))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
|
for (const Scope * const scope : symbolDatabase->functionScopes) {
|
||||||
|
for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
|
||||||
|
if (!tok->function() || !Token::Match(tok, "%name% ("))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If argument is '%type% a[num]' then check bounds against num
|
||||||
|
const Function *callfunc = tok->function();
|
||||||
|
const std::vector<const Token *> callargs = getArguments(tok);
|
||||||
|
for (nonneg int paramIndex = 0; paramIndex < callargs.size() && paramIndex < callfunc->argCount(); ++paramIndex) {
|
||||||
|
const Variable* const argument = callfunc->getArgumentVar(paramIndex);
|
||||||
|
if (!argument || !argument->nameToken() || !argument->isArray())
|
||||||
|
continue;
|
||||||
|
if (!argument->valueType() || !callargs[paramIndex]->valueType())
|
||||||
|
continue;
|
||||||
|
if (argument->valueType()->type != callargs[paramIndex]->valueType()->type)
|
||||||
|
continue;
|
||||||
|
const Token * calldata = callargs[paramIndex];
|
||||||
|
while (Token::Match(calldata, "::|."))
|
||||||
|
calldata = calldata->astOperand2();
|
||||||
|
if (!calldata->variable() || !calldata->variable()->isArray())
|
||||||
|
continue;
|
||||||
|
if (calldata->variable()->dimensions().size() != argument->dimensions().size())
|
||||||
|
continue;
|
||||||
|
bool err = false;
|
||||||
|
for (int d = 0; d < argument->dimensions().size(); ++d) {
|
||||||
|
const auto& dim1 = calldata->variable()->dimensions()[d];
|
||||||
|
const auto& dim2 = argument->dimensions()[d];
|
||||||
|
if (!dim1.known || !dim2.known)
|
||||||
|
break;
|
||||||
|
if (dim1.num < dim2.num)
|
||||||
|
err = true;
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
argumentSizeError(tok, tok->str(), argument->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckBufferOverrun::argumentSizeError(const Token *tok, const std::string &functionName, const std::string &varname)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::warning, "argumentSize",
|
||||||
|
"$symbol:" + functionName + '\n' +
|
||||||
|
"$symbol:" + varname + '\n' +
|
||||||
|
"The array '" + varname + "' is too small, the function '" + functionName + "' expects a bigger one.", CWE_ARGUMENT_SIZE, Certainty::normal);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// CTU..
|
// CTU..
|
||||||
|
|
|
@ -74,6 +74,7 @@ public:
|
||||||
checkBufferOverrun.arrayIndexThenCheck();
|
checkBufferOverrun.arrayIndexThenCheck();
|
||||||
checkBufferOverrun.stringNotZeroTerminated();
|
checkBufferOverrun.stringNotZeroTerminated();
|
||||||
checkBufferOverrun.objectIndex();
|
checkBufferOverrun.objectIndex();
|
||||||
|
checkBufferOverrun.argumentSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
|
||||||
|
@ -84,6 +85,7 @@ public:
|
||||||
c.arrayIndexThenCheckError(nullptr, "i");
|
c.arrayIndexThenCheckError(nullptr, "i");
|
||||||
c.bufferOverflowError(nullptr, nullptr, Certainty::normal);
|
c.bufferOverflowError(nullptr, nullptr, Certainty::normal);
|
||||||
c.objectIndexError(nullptr, nullptr, true);
|
c.objectIndexError(nullptr, nullptr, true);
|
||||||
|
c.argumentSizeError(nullptr, "function", "buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Parse current TU and extract file info */
|
/** @brief Parse current TU and extract file info */
|
||||||
|
@ -114,6 +116,9 @@ private:
|
||||||
void stringNotZeroTerminated();
|
void stringNotZeroTerminated();
|
||||||
void terminateStrncpyError(const Token *tok, const std::string &varname);
|
void terminateStrncpyError(const Token *tok, const std::string &varname);
|
||||||
|
|
||||||
|
void argumentSize();
|
||||||
|
void argumentSizeError(const Token *tok, const std::string &functionName, const std::string &varname);
|
||||||
|
|
||||||
void objectIndex();
|
void objectIndex();
|
||||||
void objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known);
|
void objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known);
|
||||||
|
|
||||||
|
@ -153,7 +158,8 @@ private:
|
||||||
"- Buffer overflow\n"
|
"- Buffer overflow\n"
|
||||||
"- Dangerous usage of strncat()\n"
|
"- Dangerous usage of strncat()\n"
|
||||||
"- Using array index before checking it\n"
|
"- Using array index before checking it\n"
|
||||||
"- Partial string write that leads to buffer that is not zero terminated.\n";
|
"- Partial string write that leads to buffer that is not zero terminated.\n"
|
||||||
|
"- Check for large enough arrays being passed to functions\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -2855,28 +2855,21 @@ private:
|
||||||
" char a[2];\n"
|
" char a[2];\n"
|
||||||
" f(a);\n"
|
" f(a);\n"
|
||||||
"}");
|
"}");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", "", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", errout.str());
|
||||||
|
|
||||||
check("void f(float a[10][3]);\n"
|
check("void f(float a[10][3]);\n"
|
||||||
"void g() {\n"
|
"void g() {\n"
|
||||||
" float a[2][3];\n"
|
" float a[2][3];\n"
|
||||||
" f(a);\n"
|
" f(a);\n"
|
||||||
"}");
|
"}");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", "", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", errout.str());
|
||||||
|
|
||||||
check("void f(int a[20]);\n"
|
check("void f(int a[20]);\n"
|
||||||
"void g() {\n"
|
"void g() {\n"
|
||||||
" int a[2];\n"
|
" int a[2];\n"
|
||||||
" f(a);\n"
|
" f(a);\n"
|
||||||
"}");
|
"}");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", "", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", errout.str());
|
||||||
|
|
||||||
check("void f(int a[20]);\n"
|
|
||||||
"void g() {\n"
|
|
||||||
" int a[5];\n"
|
|
||||||
" f(a);\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check("void f(int a[]) {\n"
|
check("void f(int a[]) {\n"
|
||||||
" switch (2) {\n"
|
" switch (2) {\n"
|
||||||
|
|
Loading…
Reference in New Issue