Fix 10843: FP: danglingTemporaryLifetime (#3908)
* Fix 10843: FP: danglingTemporaryLifetime * Format
This commit is contained in:
parent
fb1170b10b
commit
40ff9edad6
|
@ -3268,9 +3268,6 @@ static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
|
||||||
return true;
|
return true;
|
||||||
if (vtParent->str() == vt->str())
|
if (vtParent->str() == vt->str())
|
||||||
return true;
|
return true;
|
||||||
if (vtParent->pointer == vt->pointer && vtParent->type == vt->type && vtParent->isIntegral())
|
|
||||||
// sign conversion
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -3345,42 +3342,6 @@ static bool isDifferentType(const Token* src, const Token* dst)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<ValueType> getParentValueTypes(const Token* tok, const Settings* settings = nullptr)
|
|
||||||
{
|
|
||||||
if (!tok)
|
|
||||||
return {};
|
|
||||||
if (!tok->astParent())
|
|
||||||
return {};
|
|
||||||
if (Token::Match(tok->astParent(), "(|{|,")) {
|
|
||||||
int argn = -1;
|
|
||||||
const Token* ftok = getTokenArgumentFunction(tok, argn);
|
|
||||||
if (ftok && ftok->function()) {
|
|
||||||
std::vector<ValueType> result;
|
|
||||||
std::vector<const Variable*> argsVars = getArgumentVars(ftok, argn);
|
|
||||||
for (const Variable* var : getArgumentVars(ftok, argn)) {
|
|
||||||
if (!var)
|
|
||||||
continue;
|
|
||||||
if (!var->valueType())
|
|
||||||
continue;
|
|
||||||
result.push_back(*var->valueType());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (settings && Token::Match(tok->astParent()->tokAt(-2), ". push_back|push_front|insert|push (") &&
|
|
||||||
astIsContainer(tok->astParent()->tokAt(-2)->astOperand1())) {
|
|
||||||
const Token* contTok = tok->astParent()->tokAt(-2)->astOperand1();
|
|
||||||
const ValueType* vtCont = contTok->valueType();
|
|
||||||
if (!vtCont->containerTypeToken)
|
|
||||||
return {};
|
|
||||||
ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
|
|
||||||
return {std::move(vtParent)};
|
|
||||||
}
|
|
||||||
if (tok->astParent()->valueType())
|
|
||||||
return {*tok->astParent()->valueType()};
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isInConstructorList(const Token* tok)
|
static bool isInConstructorList(const Token* tok)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
|
@ -3400,6 +3361,58 @@ static bool isInConstructorList(const Token* tok)
|
||||||
return Token::simpleMatch(parent, ":") && !Token::simpleMatch(parent->astParent(), "?");
|
return Token::simpleMatch(parent, ":") && !Token::simpleMatch(parent->astParent(), "?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<ValueType> getParentValueTypes(const Token* tok,
|
||||||
|
const Settings* settings = nullptr,
|
||||||
|
const Token** parent = nullptr)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return {};
|
||||||
|
if (!tok->astParent())
|
||||||
|
return {};
|
||||||
|
if (isInConstructorList(tok)) {
|
||||||
|
if (parent)
|
||||||
|
*parent = tok->astParent()->astOperand1();
|
||||||
|
if (tok->astParent()->astOperand1()->valueType())
|
||||||
|
return {*tok->astParent()->astOperand1()->valueType()};
|
||||||
|
return {};
|
||||||
|
} else if (Token::Match(tok->astParent(), "(|{|,")) {
|
||||||
|
int argn = -1;
|
||||||
|
const Token* ftok = getTokenArgumentFunction(tok, argn);
|
||||||
|
if (ftok && ftok->function()) {
|
||||||
|
std::vector<ValueType> result;
|
||||||
|
std::vector<const Variable*> argsVars = getArgumentVars(ftok, argn);
|
||||||
|
const Token* nameTok = nullptr;
|
||||||
|
for (const Variable* var : getArgumentVars(ftok, argn)) {
|
||||||
|
if (!var)
|
||||||
|
continue;
|
||||||
|
if (!var->valueType())
|
||||||
|
continue;
|
||||||
|
nameTok = var->nameToken();
|
||||||
|
result.push_back(*var->valueType());
|
||||||
|
}
|
||||||
|
if (result.size() == 1 && nameTok && parent) {
|
||||||
|
*parent = nameTok;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settings && Token::Match(tok->astParent()->tokAt(-2), ". push_back|push_front|insert|push (") &&
|
||||||
|
astIsContainer(tok->astParent()->tokAt(-2)->astOperand1())) {
|
||||||
|
const Token* contTok = tok->astParent()->tokAt(-2)->astOperand1();
|
||||||
|
const ValueType* vtCont = contTok->valueType();
|
||||||
|
if (!vtCont->containerTypeToken)
|
||||||
|
return {};
|
||||||
|
ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
|
||||||
|
return {std::move(vtParent)};
|
||||||
|
}
|
||||||
|
if (Token::Match(tok->astParent(), "return|(|{|%assign%") && parent) {
|
||||||
|
*parent = tok->astParent();
|
||||||
|
}
|
||||||
|
if (tok->astParent()->valueType())
|
||||||
|
return {*tok->astParent()->valueType()};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool isLifetimeBorrowed(const Token *tok, const Settings *settings)
|
bool isLifetimeBorrowed(const Token *tok, const Settings *settings)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
|
@ -3408,42 +3421,21 @@ bool isLifetimeBorrowed(const Token *tok, const Settings *settings)
|
||||||
return true;
|
return true;
|
||||||
if (!tok->astParent())
|
if (!tok->astParent())
|
||||||
return true;
|
return true;
|
||||||
if (isInConstructorList(tok)) {
|
const Token* parent = nullptr;
|
||||||
const Token* parent = tok->astParent()->astOperand1();
|
const ValueType* vt = tok->valueType();
|
||||||
const ValueType* vt = tok->valueType();
|
std::vector<ValueType> vtParents = getParentValueTypes(tok, settings, &parent);
|
||||||
const ValueType* vtParent = parent->valueType();
|
if (vt) {
|
||||||
if (isLifetimeBorrowed(vt, vtParent))
|
for (const ValueType& vtParent : vtParents) {
|
||||||
return true;
|
if (isLifetimeBorrowed(vt, &vtParent))
|
||||||
if (isLifetimeOwned(vt, vtParent))
|
return true;
|
||||||
return false;
|
if (isLifetimeOwned(vt, &vtParent))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parent) {
|
||||||
if (isDifferentType(tok, parent))
|
if (isDifferentType(tok, parent))
|
||||||
return false;
|
return false;
|
||||||
} else if (!Token::Match(tok->astParent()->previous(), "%name% (") && !Token::simpleMatch(tok->astParent(), ",")) {
|
|
||||||
if (!Token::simpleMatch(tok, "{")) {
|
|
||||||
const ValueType *vt = tok->valueType();
|
|
||||||
const ValueType *vtParent = tok->astParent()->valueType();
|
|
||||||
if (isLifetimeBorrowed(vt, vtParent))
|
|
||||||
return true;
|
|
||||||
if (isLifetimeOwned(vt, vtParent))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (Token::Match(tok->astParent(), "return|(|{|%assign%")) {
|
|
||||||
if (isDifferentType(tok, tok->astParent()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (Token::Match(tok->astParent()->tokAt(-3), "%var% . push_back|push_front|insert|push (") &&
|
|
||||||
astIsContainer(tok->astParent()->tokAt(-3))) {
|
|
||||||
const ValueType *vt = tok->valueType();
|
|
||||||
const ValueType *vtCont = tok->astParent()->tokAt(-3)->valueType();
|
|
||||||
if (!vtCont->containerTypeToken)
|
|
||||||
return true;
|
|
||||||
ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
|
|
||||||
if (isLifetimeBorrowed(vt, &vtParent))
|
|
||||||
return true;
|
|
||||||
if (isLifetimeOwned(vt, &vtParent))
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4063,15 +4055,13 @@ static void valueFlowLifetimeConstructor(Token* tok,
|
||||||
const Token* expr = tok2->astOperand2();
|
const Token* expr = tok2->astOperand2();
|
||||||
if (!var)
|
if (!var)
|
||||||
continue;
|
continue;
|
||||||
if (!isLifetimeBorrowed(expr, settings))
|
|
||||||
continue;
|
|
||||||
const Variable* argvar = getLifetimeVariable(expr);
|
const Variable* argvar = getLifetimeVariable(expr);
|
||||||
if (!argvar)
|
if (var->isReference() || var->isRValueReference()) {
|
||||||
argvar = expr->variable();
|
if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
|
||||||
if (argvar && argvar->isArgument()) {
|
paramCapture[argvar] = LifetimeCapture::ByReference;
|
||||||
paramCapture[argvar] =
|
}
|
||||||
argvar->isReference() ? LifetimeCapture::ByReference : LifetimeCapture::ByValue;
|
} else {
|
||||||
} else if (!var->isReference()) {
|
bool found = false;
|
||||||
for (const ValueFlow::Value& v : expr->values()) {
|
for (const ValueFlow::Value& v : expr->values()) {
|
||||||
if (!v.isLifetimeValue())
|
if (!v.isLifetimeValue())
|
||||||
continue;
|
continue;
|
||||||
|
@ -4082,12 +4072,18 @@ static void valueFlowLifetimeConstructor(Token* tok,
|
||||||
const Variable* lifeVar = v.tokvalue->variable();
|
const Variable* lifeVar = v.tokvalue->variable();
|
||||||
if (!lifeVar)
|
if (!lifeVar)
|
||||||
continue;
|
continue;
|
||||||
if (!lifeVar->isArgument())
|
LifetimeCapture c = LifetimeCapture::Undefined;
|
||||||
continue;
|
if (!v.isArgumentLifetimeValue() && (lifeVar->isReference() || lifeVar->isRValueReference()))
|
||||||
if (!lifeVar->isReference())
|
c = LifetimeCapture::ByReference;
|
||||||
continue;
|
else if (v.isArgumentLifetimeValue())
|
||||||
paramCapture[lifeVar] = LifetimeCapture::ByReference;
|
c = LifetimeCapture::ByValue;
|
||||||
|
if (c != LifetimeCapture::Undefined) {
|
||||||
|
paramCapture[lifeVar] = c;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!found && argvar && argvar->isArgument())
|
||||||
|
paramCapture[argvar] = LifetimeCapture::ByValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Use SubExpressionAnalyzer for members
|
// TODO: Use SubExpressionAnalyzer for members
|
||||||
|
|
|
@ -3197,6 +3197,27 @@ private:
|
||||||
" return A{0};\n"
|
" return A{0};\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
TODO_ASSERT_EQUALS("error", "", errout.str());
|
TODO_ASSERT_EQUALS("error", "", errout.str());
|
||||||
|
|
||||||
|
check("struct A {\n"
|
||||||
|
" int n;\n"
|
||||||
|
" A(const int &x) : n(x) {}\n"
|
||||||
|
"};\n"
|
||||||
|
"A f() {\n"
|
||||||
|
" A m(4);\n"
|
||||||
|
" return m;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("struct B {};\n"
|
||||||
|
"struct A {\n"
|
||||||
|
" B n;\n"
|
||||||
|
" A(const B &x) : n(x) {}\n"
|
||||||
|
"};\n"
|
||||||
|
"A f() {\n"
|
||||||
|
" A m(B{});\n"
|
||||||
|
" return m;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void danglingLifetimeAggegrateConstructor() {
|
void danglingLifetimeAggegrateConstructor() {
|
||||||
|
|
Loading…
Reference in New Issue