From 991bf7e66c89875360c6b762e4ae246f57475cfc Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 17 Sep 2022 22:28:02 -0500 Subject: [PATCH 1/2] Fix 11298: FP danglingTemporaryLifetime when constructing from const char* --- lib/valueflow.cpp | 29 +++++++++++++++++++++++++++-- test/testautovariables.cpp | 19 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index b77aa94811d..09997405a87 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4014,6 +4014,31 @@ struct LifetimeStore { } }; +static bool isOwningVariables(const std::list& 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 args = getArguments(tok); if (scope->numConstructors == 0) { diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 9a97dafb8fa..dc444ac5406 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -3656,6 +3656,25 @@ class TestAutoVariables : public TestFixture { " 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() From 988d686ade0fe241b8c5bffd4fd0083a6a143f05 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 17 Sep 2022 22:28:47 -0500 Subject: [PATCH 2/2] Format --- lib/valueflow.cpp | 4 ++-- test/testautovariables.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 09997405a87..98f07353c26 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4014,7 +4014,7 @@ struct LifetimeStore { } }; -static bool isOwningVariables(const std::list& vars, int depth=10) +static bool isOwningVariables(const std::list& vars, int depth = 10) { if (depth < 0) return false; @@ -4033,7 +4033,7 @@ static bool isOwningVariables(const std::list& vars, int depth=10) if (vt->type == ValueType::CONTAINER && vt->container) return !vt->container->view; if (vt->typeScope) - return isOwningVariables(vt->typeScope->varlist, depth-1); + return isOwningVariables(vt->typeScope->varlist, depth - 1); } return false; }); diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index dc444ac5406..47adcba6981 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -3673,7 +3673,8 @@ class TestAutoVariables : public TestFixture { "void T::f() {\n" " U u(p->g().c_str());\n" " if (u.h()) {}\n" - "}\n", true); + "}\n", + true); ASSERT_EQUALS("", errout.str()); }