diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 88ba82617..369759174 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -311,6 +311,23 @@ Token* astParentSkipParens(Token* tok) return astParentSkipParens(parent); } +const Token* getParentMember(const Token * tok) +{ + if (!tok) + return tok; + const Token * parent = tok->astParent(); + if (!Token::simpleMatch(parent, ".")) + return tok; + if (tok == parent->astOperand2()) + return parent->astOperand1(); + const Token * gparent = parent->astParent(); + if (!Token::simpleMatch(gparent, ".") || gparent->astOperand2() != parent) + return tok; + if (gparent->astOperand1()) + return gparent->astOperand1(); + return tok; +} + static const Token * getVariableInitExpression(const Variable * var) { if (!var || !var->declEndToken()) diff --git a/lib/astutils.h b/lib/astutils.h index fc25a7efa..28e22c866 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -94,6 +94,8 @@ const Token * nextAfterAstRightmostLeaf(const Token * tok); Token* astParentSkipParens(Token* tok); const Token* astParentSkipParens(const Token* tok); +const Token* getParentMember(const Token * tok); + bool precedes(const Token * tok1, const Token * tok2); bool exprDependsOnThis(const Token* expr, nonneg int depth = 0); diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index e97eb1b11..1f5f66cfc 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -433,6 +433,22 @@ static bool isDeadScope(const Token * tok, const Scope * scope) return false; } +static const Token * getParentLifetime(const Token *tok) +{ + if (!tok) + return tok; + const Variable * var = tok->variable(); + // TODO: Call getLifetimeVariable for deeper analysis + if (!var) + return tok; + if (var->isLocal()) + return tok; + const Token * parent = getParentMember(tok); + if (parent != tok) + return getParentLifetime(parent); + return tok; +} + static int getPointerDepth(const Token *tok) { if (!tok) @@ -489,23 +505,24 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token for (const ValueFlow::Value& val:tok->values()) { if (!val.isLocalLifetimeValue()) continue; + const Token * tokvalue = getParentLifetime(val.tokvalue); if (Token::Match(tok->astParent(), "return|throw")) { - if (getPointerDepth(tok) < getPointerDepth(val.tokvalue)) + if (getPointerDepth(tok) < getPointerDepth(tokvalue)) continue; if (!isLifetimeBorrowed(tok, mSettings)) continue; - if ((val.tokvalue->variable() && isInScope(val.tokvalue->variable()->nameToken(), scope)) || - isDeadTemporary(mTokenizer->isCPP(), val.tokvalue, tok, &mSettings->library)) { + if ((tokvalue->variable() && isInScope(tokvalue->variable()->nameToken(), scope)) || + isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) { errorReturnDanglingLifetime(tok, &val); break; } - } else if (val.tokvalue->variable() && isDeadScope(val.tokvalue->variable()->nameToken(), tok->scope())) { + } else if (tokvalue->variable() && isDeadScope(tokvalue->variable()->nameToken(), tok->scope())) { errorInvalidLifetime(tok, &val); break; - } else if (!val.tokvalue->variable() && isDeadTemporary(mTokenizer->isCPP(), val.tokvalue, tok, &mSettings->library)) { + } else if (!tokvalue->variable() && isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) { errorDanglingTemporaryLifetime(tok, &val); break; - } else if (val.tokvalue->variable() && isInScope(val.tokvalue->variable()->nameToken(), tok->scope())) { + } else if (tokvalue->variable() && isInScope(tokvalue->variable()->nameToken(), tok->scope())) { const Variable * var = nullptr; const Token * tok2 = tok; if (Token::simpleMatch(tok->astParent(), "=")) { diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index a459ad1b1..29bbceebd 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3772,6 +3772,8 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger const Variable *var = varTok->variable(); if (!var) return false; + if (!var->isLocal() && !var->isArgument()) + return false; const Scope *scope = var->scope(); if (!scope) return false; diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 4b4939e0e..0631db6ff 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -2197,6 +2197,14 @@ private: " m = msg;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #9201 + check("int* f() {\n" + " struct a { int m; };\n" + " static a b{0};\n" + " return &b.m;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void danglingLifetimeFunction() { @@ -2502,6 +2510,20 @@ private: check("int &a[];\n" "void b(){int *c = a};\n"); ASSERT_EQUALS("", errout.str()); + + check("struct A {\n" + " int x;\n" + "};\n" + "struct B {\n" + " std::function x;\n" + " void f() {\n" + " this->x = [&] {\n" + " B y;\n" + " return y.x;\n" + " };\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); } void deadPointer() {