diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 8bb66833e..9693c3188 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -279,6 +279,26 @@ void CheckAutoVariables::autoVariables() errorAutoVariableAssignment(tok->next(), false); } // Critical return + else if (Token::Match(tok, "return %var% ;") && isAutoVar(tok->next())) { + const std::list &values = tok->next()->values(); + const ValueFlow::Value *value = nullptr; + for (std::list::const_iterator it = values.begin(); it != values.end(); ++it) { + if (!it->isTokValue()) + continue; + if (!_settings->inconclusive && it->isInconclusive()) + continue; + if (!Token::Match(it->tokvalue->previous(), "= & %var%")) + continue; + if (!isAutoVar(it->tokvalue->next())) + continue; + if (!value || value->isInconclusive()) + value = &(*it); + } + + if (value) + errorReturnAddressToAutoVariable(tok, value); + } + else if (Token::Match(tok, "return & %var% ;")) { const Token* varTok = tok->tokAt(2); if (isAutoVar(varTok)) @@ -336,6 +356,11 @@ void CheckAutoVariables::errorReturnAddressToAutoVariable(const Token *tok) reportError(tok, Severity::error, "returnAddressOfAutoVariable", "Address of an auto-variable returned.", CWE562, false); } +void CheckAutoVariables::errorReturnAddressToAutoVariable(const Token *tok, const ValueFlow::Value *value) +{ + reportError(tok, Severity::error, "returnAddressOfAutoVariable", "Address of auto-variable '" + value->tokvalue->astOperand1()->expressionString() + "' returned", CWE562, false); +} + void CheckAutoVariables::errorReturnPointerToLocalArray(const Token *tok) { reportError(tok, Severity::error, "returnLocalVariable", "Pointer to local array variable returned.", CWE562, false); diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index c2306f791..98167016b 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.h @@ -82,6 +82,7 @@ private: static bool returnTemporary(const Token *tok); void errorReturnAddressToAutoVariable(const Token *tok); + void errorReturnAddressToAutoVariable(const Token *tok, const ValueFlow::Value *value); void errorAssignAddressOfLocalArrayToGlobalPointer(const Token *pointer, const Token *array); void errorAssignAddressOfLocalVariableToGlobalPointer(const Token *pointer, const Token *variable); void errorReturnPointerToLocalArray(const Token *tok); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e700446e4..3c34d5b9c 100755 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -7035,6 +7035,7 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign // return variable.. if (Token::Match(tok3, "return %varid% %any%", varid) && + valueToken->str() != "&" && (tok3->tokAt(2)->isExtendedOp() || tok3->strAt(2) == ";") && value[0] != '\"') { tok3->next()->str(value); diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 75e3f5de8..0e6fe5e3f 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -95,6 +95,7 @@ private: TEST_CASE(returnLocalVariable3); // &x[0] TEST_CASE(returnLocalVariable4); // x+y TEST_CASE(returnLocalVariable5); // cast + TEST_CASE(returnLocalVariable6); // valueflow // return reference.. TEST_CASE(returnReference1); @@ -755,6 +756,14 @@ private: ASSERT_EQUALS("[test.cpp:3]: (error) Pointer to local array variable returned.\n", errout.str()); } + void returnLocalVariable6() { // valueflow + check("int *foo() {\n" + " int x = 123;\n" + " int p = &x;\n" + " return p;\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (error) Address of auto-variable 'x' returned\n", errout.str()); + } void returnReference1() { check("std::string &foo()\n"