diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index cc8ed4d27..1c829b156 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -82,8 +82,20 @@ bool CheckAutoVariables::isAutoVarArray(const Token *tok) } // Verification that we really take the address of a local variable -static bool checkRvalueExpression(const Variable* var, const Token* next) +static bool checkRvalueExpression(const Token * const vartok) { + const Variable * const var = vartok->variable(); + if (var == NULL) + return false; + + const Token * const next = vartok->next(); + + // &a.b[0] + if (Token::Match(vartok, "%var% . %var% [") && !var->isPointer()) { + const Variable *var2 = next->next()->variable(); + return var2 && !var2->isPointer(); + } + return((next->str() != "." || (!var->isPointer() && (!var->isClass() || var->type()))) && next->strAt(2) != "."); } @@ -112,12 +124,10 @@ void CheckAutoVariables::autoVariables() for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { // Critical assignment if (Token::Match(tok, "[;{}] %var% = & %var%") && isRefPtrArg(tok->next()) && isAutoVar(tok->tokAt(4))) { - const Variable * var = tok->tokAt(4)->variable(); - if (checkRvalueExpression(var, tok->tokAt(5))) + if (checkRvalueExpression(tok->tokAt(4))) errorAutoVariableAssignment(tok->next(), false); } else if (Token::Match(tok, "[;{}] * %var% = & %var%") && isPtrArg(tok->tokAt(2)) && isAutoVar(tok->tokAt(5))) { - const Variable * var = tok->tokAt(5)->variable(); - if (checkRvalueExpression(var, tok->tokAt(6))) + if (checkRvalueExpression(tok->tokAt(5))) errorAutoVariableAssignment(tok->next(), false); } else if (reportWarnings && Token::Match(tok, "[;{}] %var% =") && @@ -129,8 +139,8 @@ void CheckAutoVariables::autoVariables() if (_settings->inconclusive) { const Variable * var1 = tok->next()->variable(); if (var1 && var1->isArgument() && var1->isPointer()) { - const Variable * var2 = tok->tokAt(6)->variable(); - if (isAutoVar(tok->tokAt(6)) && checkRvalueExpression(var2, tok->tokAt(7))) + const Token * const var2tok = tok->tokAt(6); + if (isAutoVar(var2tok) && checkRvalueExpression(var2tok)) errorAutoVariableAssignment(tok->next(), true); } } @@ -154,8 +164,7 @@ void CheckAutoVariables::autoVariables() tok = tok->tokAt(4); } else if (Token::Match(tok, "[;{}] %var% [") && Token::Match(tok->linkAt(2), "] = & %var%") && isPtrArg(tok->next()) && isAutoVar(tok->linkAt(2)->tokAt(3))) { const Token* const varTok = tok->linkAt(2)->tokAt(3); - const Variable * var = varTok->variable(); - if (checkRvalueExpression(var, varTok->next())) + if (checkRvalueExpression(varTok)) errorAutoVariableAssignment(tok->next(), false); } // Critical return diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 84d471096..e5b9e20bb 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -77,6 +77,7 @@ private: TEST_CASE(testautovar8); TEST_CASE(testautovar9); TEST_CASE(testautovar10); // ticket #2930 - void f(char *p) { p = '\0'; } + TEST_CASE(testautovar11); // ticket #4641 - fp, assign local struct member address to function parameter TEST_CASE(testautovar_array1); TEST_CASE(testautovar_array2); TEST_CASE(testautovar_return1); @@ -305,6 +306,26 @@ private: ASSERT_EQUALS("", errout.str()); } + void testautovar11() { // #4641 - fp, assign local struct member address to function parameter + check("struct A {\n" + " char *data[10];\n" + "};\n" + "void foo(char** p) {\n" + " struct A a = bar();\n" + " *p = &a.data[0];\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("struct A {\n" + " char data[10];\n" + "};\n" + "void foo(char** p) {\n" + " struct A a = bar();\n" + " *p = &a.data[0];\n" + "}"); + ASSERT_EQUALS("[test.cpp:6]: (error) Address of local auto-variable assigned to a function parameter.\n", errout.str()); + } + void testautovar_array1() { check("void func1(int* arr[2])\n" "{\n"