diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 939ca6f62..8bb66833e 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -208,6 +208,22 @@ void CheckAutoVariables::assignFunctionArg() } } +static bool reassignedGlobalPointer(const Token *vartok, unsigned int pointerVarId) +{ + const Token * const end = vartok->variable()->typeStartToken()->scope()->classEnd; + for (const Token *tok2 = vartok; tok2 != nullptr && tok2 != end; tok2 = tok2->next()) { + if (Token::Match(tok2, "%varid% =", pointerVarId)) + return true; + if (Token::Match(tok2, "%name% (") && !Token::simpleMatch(tok2->linkAt(1), ") {")) { + // Bailout: possibly written + // TODO: check if it is written + return true; + } + } + return false; +} + + void CheckAutoVariables::autoVariables() { const bool printInconclusive = _settings->inconclusive; @@ -223,25 +239,17 @@ void CheckAutoVariables::autoVariables() } else if (Token::Match(tok, "[;{}] * %var% = & %var%") && isPtrArg(tok->tokAt(2)) && isAutoVar(tok->tokAt(5))) { if (checkRvalueExpression(tok->tokAt(5))) errorAutoVariableAssignment(tok->next(), false); - } else if (_settings->isEnabled(Settings::WARNING) && Token::Match(tok, "[;{}] %var% = %var% ;") && isGlobalPtr(tok->next()) && isAutoVarArray(tok->tokAt(3))) { + } else if (_settings->isEnabled(Settings::WARNING) && Token::Match(tok, "[;{}] %var% = &| %var% ;") && isGlobalPtr(tok->next())) { 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 (isAutoVarArray(tok->tokAt(3))) { + const Token * const array = tok->tokAt(3); + if (!reassignedGlobalPointer(array, pointer->varId())) + errorAssignAddressOfLocalArrayToGlobalPointer(pointer, array); + } else if (isAutoVar(tok->tokAt(4))) { + const Token * const variable = tok->tokAt(4); + if (!reassignedGlobalPointer(variable, pointer->varId())) + errorAssignAddressOfLocalVariableToGlobalPointer(pointer, variable); } - if (!writtenAgain) - errorAssignAddressOfLocalArrayToGlobalPointer(pointer, array); } else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%")) { // TODO: check if the parameter is only changed temporarily (#2969) if (printInconclusive && isPtrArg(tok->next())) { @@ -362,6 +370,14 @@ void CheckAutoVariables::errorAssignAddressOfLocalArrayToGlobalPointer(const Tok "Address of local array " + arrayName + " is assigned to global pointer " + pointerName +" and not reassigned before " + arrayName + " goes out of scope.", CWE562, false); } +void CheckAutoVariables::errorAssignAddressOfLocalVariableToGlobalPointer(const Token *pointer, const Token *variable) +{ + const std::string pointerName = pointer ? pointer->str() : std::string("pointer"); + const std::string variableName = variable ? variable->str() : std::string("variable"); + reportError(pointer, Severity::warning, "autoVariablesAssignGlobalPointer", + "Address of local variable " + variableName + " is assigned to global pointer " + pointerName +" and not reassigned before " + variableName + " goes out of scope.", CWE562, false); +} + void CheckAutoVariables::errorReturnAddressOfFunctionParameter(const Token *tok, const std::string &varname) { reportError(tok, Severity::error, "returnAddressOfFunctionParameter", diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index b1c103cb7..c2306f791 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.h @@ -83,6 +83,7 @@ private: void errorReturnAddressToAutoVariable(const Token *tok); void errorAssignAddressOfLocalArrayToGlobalPointer(const Token *pointer, const Token *array); + void errorAssignAddressOfLocalVariableToGlobalPointer(const Token *pointer, const Token *variable); void errorReturnPointerToLocalArray(const Token *tok); void errorAutoVariableAssignment(const Token *tok, bool inconclusive); void errorReturnReference(const Token *tok); diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index f82fc2c1d..75e3f5de8 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -88,6 +88,7 @@ private: TEST_CASE(testassign2); // Ticket #2765 TEST_CASE(assignAddressOfLocalArrayToGlobalPointer); + TEST_CASE(assignAddressOfLocalVariableToGlobalPointer); TEST_CASE(returnLocalVariable1); TEST_CASE(returnLocalVariable2); @@ -642,6 +643,23 @@ private: ASSERT_EQUALS("", errout.str()); } + void assignAddressOfLocalVariableToGlobalPointer() { + check("int *p;\n" + "void f() {\n" + " int x;\n" + " p = &x;\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (warning) Address of local variable 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;\n" + " p = &x;\n" + " p = 0;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void returnLocalVariable1() { check("char *foo()\n" "{\n"