diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 7bc83e510..649a17835 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -473,6 +473,25 @@ static bool isEscapedReference(const Variable* var) return !isTemporary(true, vartok, nullptr, false); } +static bool isDanglingSubFunction(const Token* tokvalue, const Token* tok) +{ + if (!tokvalue) + return false; + const Variable* var = tokvalue->variable(); + if (!var->isLocal()) + return false; + Function* f = Scope::nestedInFunction(tok->scope()); + if (!f) + return false; + const Token* parent = tokvalue->astParent(); + while(parent && !Token::Match(parent->previous(), "%name% (")) { + parent = parent->astParent(); + } + if (!Token::simpleMatch(parent, "(")) + return false; + return exprDependsOnThis(parent); +} + void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end) { if (!start) @@ -537,7 +556,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token } } if (tokvalue->variable() && (isInScope(tokvalue->variable()->nameToken(), tok->scope()) || - (val.isSubFunctionLifetimeValue() && tokvalue->variable()->isLocal()))) { + (val.isSubFunctionLifetimeValue() && isDanglingSubFunction(tokvalue, tok)))) { const Variable * var = nullptr; const Token * tok2 = tok; if (Token::simpleMatch(tok->astParent(), "=")) { diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 4d13d9293..39658f51e 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1040,6 +1040,17 @@ public: return false; } + static Function* nestedInFunction(const Scope* scope) { + while(scope) { + if (scope->type == Scope::eFunction) + break; + scope = scope->nestedIn; + } + if (!scope) + return nullptr; + return scope->function; + } + bool isClassOrStruct() const { return (type == eClass || type == eStruct); } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index be8e62b1b..7d2bcf09b 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -2170,6 +2170,32 @@ private: ASSERT_EQUALS( "[test.cpp:8] -> [test.cpp:8] -> [test.cpp:4] -> [test.cpp:7] -> [test.cpp:4]: (error) Non-local variable 'v' will use object that points to local variable 'i'.\n", errout.str()); + + check("struct A {\n" + " std::vector v;\n" + " void add(int* i) {\n" + " v.push_back(i);\n" + " }\n" + "};\n" + "void f() {\n" + " A a;\n" + " int i = 0;\n" + " a.add(&i);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("struct A {\n" + " std::vector v;\n" + " void add(int* i) {\n" + " v.push_back(i);\n" + " }\n" + " void f() {\n" + " A a;\n" + " int i = 0;\n" + " a.add(&i);\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); } void danglingLifetime() {