From e6cced3181ae5819f09f445ac412ef94af6bf927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:27:19 +0200 Subject: [PATCH 1/8] add posix library to tests --- test/testclass.cpp | 2 +- test/testmemleak.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testclass.cpp b/test/testclass.cpp index 1d647eb33a1..969d5ba50ae 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -38,7 +38,7 @@ class TestClass : public TestFixture { const Settings settings0_i = settingsBuilder(settings0).certainty(Certainty::inconclusive).build(); const Settings settings1 = settingsBuilder().severity(Severity::warning).library("std.cfg").build(); const Settings settings2 = settingsBuilder().severity(Severity::style).library("std.cfg").certainty(Certainty::inconclusive).build(); - const Settings settings3 = settingsBuilder().severity(Severity::style).library("std.cfg").severity(Severity::warning).build(); + const Settings settings3 = settingsBuilder().severity(Severity::style).library("std.cfg").severity(Severity::warning).library("posix.cfg").build(); const Settings settings3_i = settingsBuilder(settings3).certainty(Certainty::inconclusive).build(); const Settings settings4 = settingsBuilder().severity(Severity::warning).severity(Severity::portability).library("std.cfg").library("posix.cfg").build(); diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 783a10ad089..5113a1f165d 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -488,7 +488,7 @@ class TestMemleakInClass : public TestFixture { TestMemleakInClass() : TestFixture("TestMemleakInClass") {} private: - const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).library("std.cfg").build(); + const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).library("std.cfg").library("posix.cfg").build(); /** * Tokenize and execute leak check for given code From 6676ad011338d35a1c343ea131cb8f7786145f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:28:22 +0200 Subject: [PATCH 2/8] unsafeClassCanLeak test --- test/testmemleak.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 5113a1f165d..959bd8afe75 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -533,6 +533,7 @@ class TestMemleakInClass : public TestFixture { TEST_CASE(class25); // ticket #4367 - false positive implementation for destructor is not seen TEST_CASE(class26); // ticket #10789 TEST_CASE(class27); // ticket #8126 + TEST_CASE(class28); TEST_CASE(staticvar); @@ -1484,6 +1485,15 @@ class TestMemleakInClass : public TestFixture { ASSERT_EQUALS("[test.cpp:6:11]: (style) Class 'S' is unsafe, 'S::a' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } + void class28() { + check("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " ~S() { /* close(m_fd); */ }\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:4:9]: (style) Class 'S' is unsafe, 'S::m_fd' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); + } + void staticvar() { check("class A\n" "{\n" From f7e5191082e992b124f0ad252436474936a449b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:28:46 +0200 Subject: [PATCH 3/8] unsafeClassCanLeak fix Co-authored-by: Aaron Danen --- lib/checkmemoryleak.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index cc8b6853f11..398240b06ab 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -517,7 +517,7 @@ void CheckMemoryLeakInClassImpl::check() // only check classes and structures for (const Scope * scope : symbolDatabase->classAndStructScopes) { for (const Variable &var : scope->varlist) { - if (!var.isStatic() && (var.isPointer() || var.isPointerArray())) { + if (!var.isStatic()) { // allocation but no deallocation of private variables in public function.. const Token *tok = var.typeStartToken(); // Either it is of standard type or a non-derived type From 6ea073d0f3bb96e692ba400cf3e8633479d0bab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:29:03 +0200 Subject: [PATCH 4/8] noCopyConstructor test --- test/testclass.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/testclass.cpp b/test/testclass.cpp index 969d5ba50ae..7ad0b3c4fc8 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -62,6 +62,7 @@ class TestClass : public TestFixture { TEST_CASE(copyConstructor4); // base class with private constructor TEST_CASE(copyConstructor5); // multiple inheritance TEST_CASE(copyConstructor6); // array of pointers + TEST_CASE(copyConstructor7); TEST_CASE(deletedMemberPointer); // deleted member pointer in destructor TEST_CASE(noOperatorEq); // class with memory management should have operator eq TEST_CASE(noDestructor); // class with memory management should have destructor @@ -1094,6 +1095,16 @@ class TestClass : public TestFixture { errout_str()); } + void copyConstructor7() { + checkCopyConstructor("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " ~S() { /* close(m_fd); */ }\n" + " S &operator =(const S&);\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a copy constructor which is recommended since it has dynamic memory/resource management. [noCopyConstructor]\n", errout_str()); + } + void deletedMemberPointer() { // delete ... From 13fb855c79a72066ab1e82a8fd38c4b6bbdd6082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:31:31 +0200 Subject: [PATCH 5/8] noOperatorEq test --- test/testclass.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/testclass.cpp b/test/testclass.cpp index 7ad0b3c4fc8..37e802e10a0 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -1169,6 +1169,15 @@ class TestClass : public TestFixture { " ~F();\n" "};"); ASSERT_EQUALS("", errout_str()); + + checkCopyConstructor("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " S(const S&);\n" + " ~S() { /* close(m_fd); */ }\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a operator= which is recommended since it has dynamic memory/resource management. [noOperatorEq]\n", errout_str()); + } void noDestructor() { From 33764cc062e57096ce0db54ad44a33da0a2db744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:31:50 +0200 Subject: [PATCH 6/8] noCopyConstructor & noOperatorEq fix --- lib/checkclass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 51d5718159f..056abb82ebb 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -473,7 +473,7 @@ void CheckClassImpl::copyconstructors() if (Token::Match(tok, "%var% ( new") || (Token::Match(tok, "%var% ( %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); - if (var && var->isPointer() && var->scope() == scope) + if (var && var->scope() == scope) allocatedVars[tok->varId()] = tok; } } @@ -481,7 +481,7 @@ void CheckClassImpl::copyconstructors() if (Token::Match(tok, "%var% = new") || (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); - if (var && var->isPointer() && var->scope() == scope && !var->isStatic()) + if (var && var->scope() == scope && !var->isStatic()) allocatedVars[tok->varId()] = tok; } } @@ -493,7 +493,7 @@ void CheckClassImpl::copyconstructors() (Token::Match(tok, "%name% ( %var%") && mSettings.library.getDeallocFuncInfo(tok))) { const Token *vartok = tok->str() == "delete" ? tok->next() : tok->tokAt(2); const Variable* var = vartok->variable(); - if (var && var->isPointer() && var->scope() == scope && !var->isStatic()) + if (var && var->scope() == scope && !var->isStatic()) deallocatedVars[vartok->varId()] = vartok; } } From 7521123cda301c958af1b524852dd9899fd4e087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 14:27:47 +0200 Subject: [PATCH 7/8] fix FP in selfcheck --- lib/checkclass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 056abb82ebb..4488b1fbec9 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -473,7 +473,7 @@ void CheckClassImpl::copyconstructors() if (Token::Match(tok, "%var% ( new") || (Token::Match(tok, "%var% ( %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); - if (var && var->scope() == scope) + if (var && var->scope() == scope && !(var->valueType() && var->valueType()->type == ValueType::SMART_POINTER)) allocatedVars[tok->varId()] = tok; } } @@ -481,7 +481,7 @@ void CheckClassImpl::copyconstructors() if (Token::Match(tok, "%var% = new") || (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); - if (var && var->scope() == scope && !var->isStatic()) + if (var && var->scope() == scope && !var->isStatic() && !(var->valueType() && var->valueType()->type == ValueType::SMART_POINTER)) allocatedVars[tok->varId()] = tok; } } From 880ac5bc470569cd1b3031439e3aee853fdfd1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 14:28:03 +0200 Subject: [PATCH 8/8] add FP test --- test/testclass.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testclass.cpp b/test/testclass.cpp index 37e802e10a0..664953f1ed3 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -63,6 +63,7 @@ class TestClass : public TestFixture { TEST_CASE(copyConstructor5); // multiple inheritance TEST_CASE(copyConstructor6); // array of pointers TEST_CASE(copyConstructor7); + TEST_CASE(copyConstructor8); TEST_CASE(deletedMemberPointer); // deleted member pointer in destructor TEST_CASE(noOperatorEq); // class with memory management should have operator eq TEST_CASE(noDestructor); // class with memory management should have destructor @@ -1105,6 +1106,15 @@ class TestClass : public TestFixture { ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a copy constructor which is recommended since it has dynamic memory/resource management. [noCopyConstructor]\n", errout_str()); } + void copyConstructor8() { + checkCopyConstructor("struct S {\n" + " S() : m_ptr(new int) {}\n" + " ~S();\n" + " std::unique_ptr m_ptr;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + } + void deletedMemberPointer() { // delete ...