LCppC backport: Restored Check: Detect negative VLA and allocation (new[]) sizes (#4187)

This commit is contained in:
PKEuS 2022-06-11 09:55:38 +02:00 committed by GitHub
parent 533b3e2bcb
commit 82af702c6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 2 deletions

View File

@ -1069,3 +1069,65 @@ void CheckBufferOverrun::objectIndexError(const Token *tok, const ValueFlow::Val
CWE758,
Certainty::normal);
}
static bool isVLAIndex(const Token* tok)
{
if (!tok)
return false;
if (tok->varId() != 0U)
return true;
if (tok->str() == "?") {
// this is a VLA index if both expressions around the ":" is VLA index
if (tok->astOperand2() &&
tok->astOperand2()->str() == ":" &&
isVLAIndex(tok->astOperand2()->astOperand1()) &&
isVLAIndex(tok->astOperand2()->astOperand2()))
return true;
return false;
}
return isVLAIndex(tok->astOperand1()) || isVLAIndex(tok->astOperand2());
}
void CheckBufferOverrun::negativeArraySize()
{
const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
for (const Variable* var : symbolDatabase->variableList()) {
if (!var || !var->isArray())
continue;
const Token* const nameToken = var->nameToken();
if (!Token::Match(nameToken, "%var% [") || !nameToken->next()->astOperand2())
continue;
const ValueFlow::Value* sz = nameToken->next()->astOperand2()->getValueLE(-1, mSettings);
// don't warn about constant negative index because that is a compiler error
if (sz && isVLAIndex(nameToken->next()->astOperand2()))
negativeArraySizeError(nameToken);
}
for (const Scope* functionScope : symbolDatabase->functionScopes) {
for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
if (!tok->isKeyword() || tok->str() != "new" || !tok->astOperand1() || tok->astOperand1()->str() != "[")
continue;
const Token* valOperand = tok->astOperand1()->astOperand2();
if (!valOperand)
continue;
const ValueFlow::Value* sz = valOperand->getValueLE(-1, mSettings);
if (sz)
negativeMemoryAllocationSizeError(tok);
}
}
}
void CheckBufferOverrun::negativeArraySizeError(const Token* tok)
{
const std::string arrayName = tok ? tok->expressionString() : std::string();
const std::string line1 = arrayName.empty() ? std::string() : ("$symbol:" + arrayName + '\n');
reportError(tok, Severity::error, "negativeArraySize",
line1 +
"Declaration of array '" + arrayName + "' with negative size is undefined behaviour", CWE758, Certainty::safe);
}
void CheckBufferOverrun::negativeMemoryAllocationSizeError(const Token* tok)
{
reportError(tok, Severity::error, "negativeMemoryAllocationSize",
"Memory allocation size is negative.", CWE131, Certainty::safe);
}

View File

@ -75,6 +75,7 @@ public:
checkBufferOverrun.stringNotZeroTerminated();
checkBufferOverrun.objectIndex();
checkBufferOverrun.argumentSize();
checkBufferOverrun.negativeArraySize();
}
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override {
@ -86,6 +87,9 @@ public:
c.bufferOverflowError(nullptr, nullptr, Certainty::normal);
c.objectIndexError(nullptr, nullptr, true);
c.argumentSizeError(nullptr, "function", 1, "buffer", nullptr, nullptr);
c.negativeMemoryAllocationSizeError(nullptr);
c.negativeArraySizeError(nullptr);
c.negativeMemoryAllocationSizeError(nullptr);
}
/** @brief Parse current TU and extract file info */
@ -119,6 +123,10 @@ private:
void argumentSize();
void argumentSizeError(const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string &paramExpression, const Variable *paramVar, const Variable *functionArg);
void negativeArraySize();
void negativeArraySizeError(const Token* tok);
void negativeMemoryAllocationSizeError(const Token* tok); // provide a negative value to memory allocation function
void objectIndex();
void objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known);
@ -159,7 +167,8 @@ private:
"- Dangerous usage of strncat()\n"
"- Using array index before checking it\n"
"- Partial string write that leads to buffer that is not zero terminated.\n"
"- Check for large enough arrays being passed to functions\n";
"- Check for large enough arrays being passed to functions\n"
"- Allocating memory with a negative size\n";
}
};
/// @}

View File

@ -1,2 +1,3 @@
release notes for cppcheck-2.9
- restored check for negative allocation (new[]) and negative VLA sizes from cppcheck 1.87 (LCppC backport)

View File

@ -4781,6 +4781,14 @@ private:
}
void negativeMemoryAllocationSizeError() { // #389
check("void f()\n"
"{\n"
" int *a;\n"
" a = new int[-1];\n"
" delete [] a;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str());
check("void f()\n"
"{\n"
" int *a;\n"
@ -4810,7 +4818,7 @@ private:
" int a[sz];\n"
"}\n"
"void x() { f(-100); }");
TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Declaration of array 'a' with negative size is undefined behaviour\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:2]: (error) Declaration of array 'a' with negative size is undefined behaviour\n", errout.str());
// don't warn for constant sizes -> this is a compiler error so this is used for static assertions for instance
check("int x, y;\n"

View File

@ -97,6 +97,8 @@ private:
TEST_CASE(returnLocalStdMove4);
TEST_CASE(returnLocalStdMove5);
TEST_CASE(negativeMemoryAllocationSizeError); // #389
}
#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
@ -1706,6 +1708,23 @@ private:
"A f2() { volatile A var; return std::move(var); }");
ASSERT_EQUALS("", errout.str());
}
void negativeMemoryAllocationSizeError() { // #389
check("void f() {\n"
" int *a;\n"
" a = malloc( -10 );\n"
" free(a);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Invalid malloc() argument nr 1. The value is -10 but the valid values are '0:'.\n", errout.str());
check("void f() {\n"
" int *a;\n"
" a = alloca( -10 );\n"
" free(a);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'alloca' called.\n"
"[test.cpp:3]: (error) Invalid alloca() argument nr 1. The value is -10 but the valid values are '0:'.\n", errout.str());
}
};
REGISTER_TEST(TestFunctions)