Skip to content

Commit

Permalink
Fix #12354 FN memleak, uninitvar with member initializer (danmar#6090)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrchr-github committed Mar 8, 2024
1 parent ff14917 commit 49897e6
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 5 deletions.
13 changes: 9 additions & 4 deletions lib/checkleakautovar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,16 @@ static const std::array<std::pair<std::string, std::string>, 4> alloc_failed_con
static const std::array<std::pair<std::string, std::string>, 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<Variable>& 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;
Expand Down
3 changes: 2 additions & 1 deletion lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions test/testleakautovar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions test/testuninitvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 49897e6

Please sign in to comment.