AutoVariables: Warn when address of local array is assigned to global pointer and pointer is not reassigned
This commit is contained in:
parent
8ce496a127
commit
599e038282
|
@ -46,35 +46,37 @@ static const CWE CWE398(398U); // Indicator of Poor Code Quality
|
||||||
static const CWE CWE562(562U); // Return of Stack Variable Address
|
static const CWE CWE562(562U); // Return of Stack Variable Address
|
||||||
static const CWE CWE590(590U); // Free of Memory not on the Heap
|
static const CWE CWE590(590U); // Free of Memory not on the Heap
|
||||||
|
|
||||||
bool CheckAutoVariables::isPtrArg(const Token *tok)
|
static bool isPtrArg(const Token *tok)
|
||||||
{
|
{
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
|
|
||||||
return (var && var->isArgument() && var->isPointer());
|
return (var && var->isArgument() && var->isPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckAutoVariables::isArrayArg(const Token *tok)
|
static bool isGlobalPtr(const Token *tok)
|
||||||
{
|
{
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
|
return (var && var->isGlobal() && var->isPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isArrayArg(const Token *tok)
|
||||||
|
{
|
||||||
|
const Variable *var = tok->variable();
|
||||||
return (var && var->isArgument() && var->isArray());
|
return (var && var->isArgument() && var->isArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckAutoVariables::isRefPtrArg(const Token *tok)
|
static bool isRefPtrArg(const Token *tok)
|
||||||
{
|
{
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
|
|
||||||
return (var && var->isArgument() && var->isReference() && var->isPointer());
|
return (var && var->isArgument() && var->isReference() && var->isPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckAutoVariables::isNonReferenceArg(const Token *tok)
|
static bool isNonReferenceArg(const Token *tok)
|
||||||
{
|
{
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
|
|
||||||
return (var && var->isArgument() && !var->isReference() && (var->isPointer() || var->typeStartToken()->isStandardType() || var->type()));
|
return (var && var->isArgument() && !var->isReference() && (var->isPointer() || var->typeStartToken()->isStandardType() || var->type()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckAutoVariables::isAutoVar(const Token *tok)
|
static bool isAutoVar(const Token *tok)
|
||||||
{
|
{
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
|
|
||||||
|
@ -98,7 +100,7 @@ bool CheckAutoVariables::isAutoVar(const Token *tok)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckAutoVariables::isAutoVarArray(const Token *tok)
|
static bool isAutoVarArray(const Token *tok)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return false;
|
return false;
|
||||||
|
@ -221,6 +223,25 @@ void CheckAutoVariables::autoVariables()
|
||||||
} else if (Token::Match(tok, "[;{}] * %var% = & %var%") && isPtrArg(tok->tokAt(2)) && isAutoVar(tok->tokAt(5))) {
|
} else if (Token::Match(tok, "[;{}] * %var% = & %var%") && isPtrArg(tok->tokAt(2)) && isAutoVar(tok->tokAt(5))) {
|
||||||
if (checkRvalueExpression(tok->tokAt(5)))
|
if (checkRvalueExpression(tok->tokAt(5)))
|
||||||
errorAutoVariableAssignment(tok->next(), false);
|
errorAutoVariableAssignment(tok->next(), false);
|
||||||
|
} else if (_settings->isEnabled(Settings::WARNING) && Token::Match(tok, "[;{}] %var% = %var% ;") && isGlobalPtr(tok->next()) && isAutoVarArray(tok->tokAt(3))) {
|
||||||
|
const Token * const pointer = tok->next();
|
||||||
|
const Token * const array = tok->tokAt(3);
|
||||||
|
const Token * const end = array->variable()->typeStartToken()->scope()->classEnd;
|
||||||
|
const unsigned int varid = pointer->varId();
|
||||||
|
bool writtenAgain = false;
|
||||||
|
for (const Token *tok2 = array; tok2 != nullptr && tok2 != end; tok2 = tok2->next()) {
|
||||||
|
if (Token::Match(tok2, "%varid% =", varid)) {
|
||||||
|
writtenAgain = true;
|
||||||
|
break;
|
||||||
|
} else if (Token::Match(tok2, "%name% (") && !Token::simpleMatch(tok2->linkAt(1), ") {")) {
|
||||||
|
// Bailout: possibly written
|
||||||
|
// TODO: check if it is written
|
||||||
|
writtenAgain = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!writtenAgain)
|
||||||
|
errorAssignAddressOfLocalArrayToGlobalPointer(pointer, array);
|
||||||
} else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%")) {
|
} else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%")) {
|
||||||
// TODO: check if the parameter is only changed temporarily (#2969)
|
// TODO: check if the parameter is only changed temporarily (#2969)
|
||||||
if (printInconclusive && isPtrArg(tok->next())) {
|
if (printInconclusive && isPtrArg(tok->next())) {
|
||||||
|
@ -333,6 +354,14 @@ void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inco
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckAutoVariables::errorAssignAddressOfLocalArrayToGlobalPointer(const Token *pointer, const Token *array)
|
||||||
|
{
|
||||||
|
const std::string pointerName = pointer ? pointer->str() : std::string("pointer");
|
||||||
|
const std::string arrayName = array ? array->str() : std::string("array");
|
||||||
|
reportError(pointer, Severity::warning, "autoVariablesAssignGlobalPointer",
|
||||||
|
"Address of local array " + arrayName + " is assigned to global pointer " + pointerName +" and not reassigned before " + arrayName + " goes out of scope.", CWE562, false);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckAutoVariables::errorReturnAddressOfFunctionParameter(const Token *tok, const std::string &varname)
|
void CheckAutoVariables::errorReturnAddressOfFunctionParameter(const Token *tok, const std::string &varname)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "returnAddressOfFunctionParameter",
|
reportError(tok, Severity::error, "returnAddressOfFunctionParameter",
|
||||||
|
|
|
@ -74,13 +74,6 @@ public:
|
||||||
void returnReference();
|
void returnReference();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool isPtrArg(const Token *tok);
|
|
||||||
static bool isArrayArg(const Token *tok);
|
|
||||||
static bool isRefPtrArg(const Token *tok);
|
|
||||||
static bool isNonReferenceArg(const Token *tok);
|
|
||||||
static bool isAutoVar(const Token *tok);
|
|
||||||
static bool isAutoVarArray(const Token *tok);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returning a temporary object?
|
* Returning a temporary object?
|
||||||
* @param tok pointing at the "return" token
|
* @param tok pointing at the "return" token
|
||||||
|
@ -89,6 +82,7 @@ private:
|
||||||
static bool returnTemporary(const Token *tok);
|
static bool returnTemporary(const Token *tok);
|
||||||
|
|
||||||
void errorReturnAddressToAutoVariable(const Token *tok);
|
void errorReturnAddressToAutoVariable(const Token *tok);
|
||||||
|
void errorAssignAddressOfLocalArrayToGlobalPointer(const Token *pointer, const Token *array);
|
||||||
void errorReturnPointerToLocalArray(const Token *tok);
|
void errorReturnPointerToLocalArray(const Token *tok);
|
||||||
void errorAutoVariableAssignment(const Token *tok, bool inconclusive);
|
void errorAutoVariableAssignment(const Token *tok, bool inconclusive);
|
||||||
void errorReturnReference(const Token *tok);
|
void errorReturnReference(const Token *tok);
|
||||||
|
@ -102,6 +96,7 @@ private:
|
||||||
CheckAutoVariables c(nullptr,settings,errorLogger);
|
CheckAutoVariables c(nullptr,settings,errorLogger);
|
||||||
c.errorAutoVariableAssignment(nullptr, false);
|
c.errorAutoVariableAssignment(nullptr, false);
|
||||||
c.errorReturnAddressToAutoVariable(nullptr);
|
c.errorReturnAddressToAutoVariable(nullptr);
|
||||||
|
c.errorAssignAddressOfLocalArrayToGlobalPointer(nullptr, nullptr);
|
||||||
c.errorReturnPointerToLocalArray(nullptr);
|
c.errorReturnPointerToLocalArray(nullptr);
|
||||||
c.errorReturnReference(nullptr);
|
c.errorReturnReference(nullptr);
|
||||||
c.errorReturnTempReference(nullptr);
|
c.errorReturnTempReference(nullptr);
|
||||||
|
|
|
@ -87,6 +87,8 @@ private:
|
||||||
TEST_CASE(testassign1); // Ticket #1819
|
TEST_CASE(testassign1); // Ticket #1819
|
||||||
TEST_CASE(testassign2); // Ticket #2765
|
TEST_CASE(testassign2); // Ticket #2765
|
||||||
|
|
||||||
|
TEST_CASE(assignAddressOfLocalArrayToGlobalPointer);
|
||||||
|
|
||||||
TEST_CASE(returnLocalVariable1);
|
TEST_CASE(returnLocalVariable1);
|
||||||
TEST_CASE(returnLocalVariable2);
|
TEST_CASE(returnLocalVariable2);
|
||||||
TEST_CASE(returnLocalVariable3); // &x[0]
|
TEST_CASE(returnLocalVariable3); // &x[0]
|
||||||
|
@ -623,6 +625,23 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assignAddressOfLocalArrayToGlobalPointer() {
|
||||||
|
check("int *p;\n"
|
||||||
|
"void f() {\n"
|
||||||
|
" int x[10];\n"
|
||||||
|
" p = x;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (warning) Address of local array x is assigned to global pointer p and not reassigned before x goes out of scope.\n", errout.str());
|
||||||
|
|
||||||
|
check("int *p;\n"
|
||||||
|
"void f() {\n"
|
||||||
|
" int x[10];\n"
|
||||||
|
" p = x;\n"
|
||||||
|
" p = 0;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void returnLocalVariable1() {
|
void returnLocalVariable1() {
|
||||||
check("char *foo()\n"
|
check("char *foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
|
Loading…
Reference in New Issue