Fix 10592: False positive: returnDanglingLifetime (#3557)
This commit is contained in:
parent
0d1d3b4ed0
commit
c057dcce0f
|
@ -259,6 +259,15 @@ bool astIsSmartPointer(const Token* tok)
|
||||||
return tok && tok->valueType() && tok->valueType()->smartPointerTypeToken;
|
return tok && tok->valueType() && tok->valueType()->smartPointerTypeToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool astIsUniqueSmartPointer(const Token* tok)
|
||||||
|
{
|
||||||
|
if (!astIsSmartPointer(tok))
|
||||||
|
return false;
|
||||||
|
if (!tok->valueType()->smartPointer)
|
||||||
|
return false;
|
||||||
|
return tok->valueType()->smartPointer->unique;
|
||||||
|
}
|
||||||
|
|
||||||
bool astIsIterator(const Token *tok)
|
bool astIsIterator(const Token *tok)
|
||||||
{
|
{
|
||||||
return tok && tok->valueType() && tok->valueType()->type == ValueType::Type::ITERATOR;
|
return tok && tok->valueType() && tok->valueType()->type == ValueType::Type::ITERATOR;
|
||||||
|
|
|
@ -82,6 +82,7 @@ bool astIsBool(const Token *tok);
|
||||||
bool astIsPointer(const Token *tok);
|
bool astIsPointer(const Token *tok);
|
||||||
|
|
||||||
bool astIsSmartPointer(const Token* tok);
|
bool astIsSmartPointer(const Token* tok);
|
||||||
|
bool astIsUniqueSmartPointer(const Token* tok);
|
||||||
|
|
||||||
bool astIsIterator(const Token *tok);
|
bool astIsIterator(const Token *tok);
|
||||||
|
|
||||||
|
|
|
@ -557,6 +557,21 @@ static const Token* getParentLifetime(bool cpp, const Token* tok, const Library*
|
||||||
if (std::any_of(it.base() - 1, members.end() - 1, [&](const Token* tok2) {
|
if (std::any_of(it.base() - 1, members.end() - 1, [&](const Token* tok2) {
|
||||||
if (astIsPointer(tok2) || astIsContainerView(tok2) || astIsIterator(tok2))
|
if (astIsPointer(tok2) || astIsContainerView(tok2) || astIsIterator(tok2))
|
||||||
return true;
|
return true;
|
||||||
|
if (!astIsUniqueSmartPointer(tok2)) {
|
||||||
|
if (astIsSmartPointer(tok2))
|
||||||
|
return true;
|
||||||
|
const Token* dotTok = tok2->next();
|
||||||
|
if (!Token::simpleMatch(dotTok, ".")) {
|
||||||
|
const Token* endTok = nextAfterAstRightmostLeaf(tok2);
|
||||||
|
if (Token::simpleMatch(endTok, "."))
|
||||||
|
dotTok = endTok;
|
||||||
|
else if (Token::simpleMatch(endTok->next(), "."))
|
||||||
|
dotTok = endTok->next();
|
||||||
|
}
|
||||||
|
// If we are dereferencing the member variable then treat it as borrowed
|
||||||
|
if (Token::simpleMatch(dotTok, ".") && dotTok->originalName() == "->")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const Variable* var = tok2->variable();
|
const Variable* var = tok2->variable();
|
||||||
return var && var->isReference();
|
return var && var->isReference();
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -2885,15 +2885,6 @@ static void valueFlowReverse(TokenList* tokenlist,
|
||||||
valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings);
|
valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUniqueSmartPointer(const Token* tok)
|
|
||||||
{
|
|
||||||
if (!astIsSmartPointer(tok))
|
|
||||||
return false;
|
|
||||||
if (!tok->valueType()->smartPointer)
|
|
||||||
return false;
|
|
||||||
return tok->valueType()->smartPointer->unique;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
|
std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
@ -3090,8 +3081,7 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
|
||||||
return {{tok, std::move(errorPath)}};
|
return {{tok, std::move(errorPath)}};
|
||||||
const Variable *tokvar = vartok->variable();
|
const Variable *tokvar = vartok->variable();
|
||||||
const bool isContainer = astIsContainer(vartok) && !astIsPointer(vartok);
|
const bool isContainer = astIsContainer(vartok) && !astIsPointer(vartok);
|
||||||
if (!isUniqueSmartPointer(vartok) && !isContainer &&
|
if (!astIsUniqueSmartPointer(vartok) && !isContainer && !(tokvar && tokvar->isArray() && !tokvar->isArgument()) &&
|
||||||
!(tokvar && tokvar->isArray() && !tokvar->isArgument()) &&
|
|
||||||
(Token::Match(vartok->astParent(), "[|*") || vartok->astParent()->originalName() == "->")) {
|
(Token::Match(vartok->astParent(), "[|*") || vartok->astParent()->originalName() == "->")) {
|
||||||
for (const ValueFlow::Value &v : vartok->values()) {
|
for (const ValueFlow::Value &v : vartok->values()) {
|
||||||
if (!v.isLocalLifetimeValue())
|
if (!v.isLocalLifetimeValue())
|
||||||
|
@ -4158,7 +4148,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
|
||||||
valueFlowLifetimeFunction(tok, tokenlist, errorLogger, settings);
|
valueFlowLifetimeFunction(tok, tokenlist, errorLogger, settings);
|
||||||
}
|
}
|
||||||
// Unique pointer lifetimes
|
// Unique pointer lifetimes
|
||||||
else if (isUniqueSmartPointer(tok) && astIsLHS(tok) && Token::simpleMatch(tok->astParent(), ". get ( )")) {
|
else if (astIsUniqueSmartPointer(tok) && astIsLHS(tok) && Token::simpleMatch(tok->astParent(), ". get ( )")) {
|
||||||
Token* ptok = tok->astParent()->tokAt(2);
|
Token* ptok = tok->astParent()->tokAt(2);
|
||||||
ErrorPath errorPath = {{ptok, "Raw pointer to smart pointer created here."}};
|
ErrorPath errorPath = {{ptok, "Raw pointer to smart pointer created here."}};
|
||||||
ValueFlow::Value value;
|
ValueFlow::Value value;
|
||||||
|
|
|
@ -2482,6 +2482,15 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"};\n");
|
"};\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("struct A {\n"
|
||||||
|
" std::map<std::string, int> m;\n"
|
||||||
|
" int* f(std::string s) {\n"
|
||||||
|
" auto r = m.emplace(name, name);\n"
|
||||||
|
" return &(r.first->second);\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void danglingLifetimeContainerView()
|
void danglingLifetimeContainerView()
|
||||||
|
|
Loading…
Reference in New Issue