Fix issue 9201: FP: returnDanglingLifetime on pointer to variable of static struct (#2303)
* Fix issue 9201: FP: returnDanglingLifetime on pointer to variable of static struct * Fix capture of non-local variables in lambdas
This commit is contained in:
parent
c61880c457
commit
d1f225b8ee
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(), "=")) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<void()> x;\n"
|
||||
" void f() {\n"
|
||||
" this->x = [&] {\n"
|
||||
" B y;\n"
|
||||
" return y.x;\n"
|
||||
" };\n"
|
||||
" }\n"
|
||||
"};\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void deadPointer() {
|
||||
|
|
Loading…
Reference in New Issue