From 49897e63e9a072887bdd87b027574a902a40b3d7 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 8 Mar 2024 10:12:00 +0100 Subject: [PATCH] Fix #12354 FN memleak, uninitvar with member initializer (#6090) --- lib/checkleakautovar.cpp | 13 +++++++++---- lib/valueflow.cpp | 3 ++- test/testleakautovar.cpp | 25 +++++++++++++++++++++++++ test/testuninitvar.cpp | 12 ++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index e85e242e79e..d20fb57b91a 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -62,11 +62,16 @@ static const std::array, 4> alloc_failed_con static const std::array, 4> alloc_success_conds {{{"!=", "0"}, {">", "0"}, {"!=", "-1"}, {">=", "0"}}}; static bool isAutoDeallocType(const Type* type) { - if (!type) + if (!type || !type->classScope) return true; - if (type->classScope && type->classScope->numConstructors == 0 && - (type->classScope->varlist.empty() || type->needInitialization == Type::NeedInitialization::True) && - std::none_of(type->derivedFrom.cbegin(), type->derivedFrom.cend(), [](const Type::BaseInfo& bi) { + if (type->classScope->numConstructors > 0) + return true; + const std::list& varlist = type->classScope->varlist; + if (std::any_of(varlist.begin(), varlist.end(), [](const Variable& v) { + return !v.valueType() || (!v.valueType()->isPrimitive() && !v.valueType()->container); + })) + return true; + if (std::none_of(type->derivedFrom.cbegin(), type->derivedFrom.cend(), [](const Type::BaseInfo& bi) { return isAutoDeallocType(bi.type); })) return false; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6e3d316318d..4cde20f8b0c 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -8084,7 +8084,8 @@ static void valueFlowUninit(TokenList& tokenlist, ErrorLogger* const errorLogger if (memVar.isArray()) continue; if (!needsInitialization(&memVar, tokenlist.isCPP())) { - partial = true; + if (!var->isPointer()) + partial = true; continue; } MemberExpressionAnalyzer analyzer(memVar.nameToken()->str(), tok, uninitValue, tokenlist, settings); diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 411ab698e6f..e7103f4c37a 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -672,6 +672,17 @@ class TestLeakAutoVar : public TestFixture { " if (d) {}\n" "}", /*cpp*/ true); ASSERT_EQUALS("[test.cpp:6]: (error) Memory leak: d\n", errout.str()); + + check("struct S {\n" // #12354 + " int i{};\n" + " void f();\n" + "};\n" + "void f(S* p, bool b) {\n" + " if (b)\n" + " p = new S();\n" + " p->f();\n" + "}", /*cpp*/ true); + ASSERT_EQUALS("[test.cpp:9]: (error) Memory leak: p\n", errout.str()); } void realloc1() { @@ -3125,6 +3136,7 @@ class TestLeakAutoVarStrcpy : public TestFixture { TEST_CASE(fclose_false_positive); // #9575 TEST_CASE(strcpy_false_negative); TEST_CASE(doubleFree); + TEST_CASE(memleak_std_string); } void returnedValue() { // #9298 @@ -3179,6 +3191,19 @@ class TestLeakAutoVarStrcpy : public TestFixture { "}\n"); ASSERT_EQUALS("", errout.str()); } + + void memleak_std_string() { + check("struct S {\n" // #12354 + " std::string s;\n" + " void f();\n" + "};\n" + "void f(S* p, bool b) {\n" + " if (b)\n" + " p = new S();\n" + " p->f();\n" + "}"); + ASSERT_EQUALS("[test.cpp:9]: (error) Memory leak: p\n", errout.str()); + } }; REGISTER_TEST(TestLeakAutoVarStrcpy) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 845810084c7..bccf0746b5e 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -7394,6 +7394,18 @@ class TestUninitVar : public TestFixture { " S s(&p);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + valueFlowUninit("struct S {\n" // #12354 + " int i{};\n" + " void f();\n" + "};\n" + "void f(bool b) {\n" + " S* p;\n" + " if (b)\n" + " p = new S();\n" + " p->f();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:9]: (warning) Uninitialized variable: p\n", errout.str()); } void uninitvar_memberfunction() {