Fix 11298: FP danglingTemporaryLifetime when constructing from const char* (#4479)

* Fix 11298: FP danglingTemporaryLifetime when constructing from const char*

* Format
This commit is contained in:
Paul Fultz II 2022-09-18 01:30:58 -05:00 committed by GitHub
parent de7d02293f
commit 09944c0b7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 2 deletions

View File

@ -4014,6 +4014,31 @@ private:
}
};
static bool isOwningVariables(const std::list<Variable>& vars, int depth = 10)
{
if (depth < 0)
return false;
return vars.empty() || std::all_of(vars.begin(), vars.end(), [&](const Variable& var) {
if (var.isReference() || var.isPointer())
return false;
const ValueType* vt = var.valueType();
if (vt) {
if (vt->pointer > 0)
return false;
if (vt->isPrimitive())
return true;
if (vt->isEnum())
return true;
// TODO: Check container inner type
if (vt->type == ValueType::CONTAINER && vt->container)
return !vt->container->view;
if (vt->typeScope)
return isOwningVariables(vt->typeScope->varlist, depth - 1);
}
return false;
});
}
static void valueFlowLifetimeUserConstructor(Token* tok,
const Function* constructor,
const std::string& name,
@ -4087,7 +4112,7 @@ static void valueFlowLifetimeUserConstructor(Token* tok,
else
ls.byVal(tok, tokenlist, errorLogger, settings);
});
} else if (!constructor->nestedIn->varlist.empty()) {
} else if (!isOwningVariables(constructor->nestedIn->varlist)) {
LifetimeStore::forEach(args,
"Passed to constructor of '" + name + "'.",
ValueFlow::Value::LifetimeKind::SubObject,
@ -4299,7 +4324,7 @@ static void valueFlowLifetimeClassConstructor(Token* tok,
const Scope* scope = t->classScope;
if (!scope)
return;
// Only support aggregate constructors for now
// Aggregate constructor
if (t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) {
std::vector<const Token*> args = getArguments(tok);
if (scope->numConstructors == 0) {

View File

@ -3656,6 +3656,26 @@ private:
" return c.get();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:7] -> [test.cpp:8]: (error) Using object that is a temporary.\n", errout.str());
// #11298
check("struct S {\n"
" std::string g(); \n"
"};\n"
"struct T {\n"
" void f(); \n"
" S* p = nullptr;\n"
"};\n"
"struct U {\n"
" explicit U(const char* s);\n"
" bool h();\n"
" int i;\n"
"};\n"
"void T::f() {\n"
" U u(p->g().c_str());\n"
" if (u.h()) {}\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
}
void danglingLifetimeBorrowedMembers()