]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
gunit/008: reset v2 mount and free duplicate mounts
authorKamalesh Babulal <kamalesh.babulal@oracle.com>
Wed, 25 Feb 2026 04:50:27 +0000 (10:20 +0530)
committerKamalesh Babulal <kamalesh.babulal@oracle.com>
Tue, 10 Mar 2026 16:38:04 +0000 (22:08 +0530)
ASan caught the v2 mount path, leaking the cg_mount_point nodes
created by cg_add_duplicate_mount() and the strdup()ed mount paths the
tests stash in struct mntent. Running make -C tests/gunit check reported:

==2840589==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 28728 byte(s) in 7 object(s) allocated from:
.../tests/gunit/008-cgroup_process_v2_mount.cpp:133

This patch adds a private ResetMountTable() helper that takes the
mount table write lock, walks each controllers linked list to free the
heap nodes, zeroes cg_mount_table, clears cg_cgroup_v2_mount_path, and
resets mnt_tbl_idx. SetUp() and TearDown() call it so each test starts
from a clean slate. The duplicate test now runs the initial mounting
step itself before it exercises the duplicate code path, and every test
frees the temporary mnt_dir strings after the checks are done.

The cleanup path now, mirrors cgroup_free_cg_mount_table() and silences
the ASan leak report while keeping the tests self-contained.

Signed-off-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
tests/gunit/008-cgroup_process_v2_mount.cpp

index 8ecef70c01d21ea17e1ffe993c7a5cf43b4ae761..a786931614a0f65e8abfa60053466ea3403e8105 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <ftw.h>
 #include <mntent.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "gtest/gtest.h"
 #include "libcgroup-internal.h"
@@ -29,6 +31,31 @@ static const int CONTROLLERS_CNT = ARRAY_SIZE(CONTROLLERS);
 static int mnt_tbl_idx = 0;
 
 class CgroupProcessV2MntTest : public ::testing::Test {
+       void ResetMountTable(void)
+       {
+               int i;
+
+               pthread_rwlock_wrlock(&cg_mount_table_lock);
+
+               for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) {
+                       struct cg_mount_point *node = cg_mount_table[i].mount.next;
+
+                       while (node) {
+                               struct cg_mount_point *tmp = node->next;
+                               free(node);
+                               node = tmp;
+                       }
+
+                       cg_mount_table[i].mount.next = NULL;
+               }
+
+               memset(cg_mount_table, 0, sizeof(cg_mount_table));
+
+               pthread_rwlock_unlock(&cg_mount_table_lock);
+
+               memset(cg_cgroup_v2_mount_path, 0, sizeof(cg_cgroup_v2_mount_path));
+               mnt_tbl_idx = 0;
+       }
        protected:
 
        void CreateHierarchy(const char * const dir)
@@ -55,6 +82,7 @@ class CgroupProcessV2MntTest : public ::testing::Test {
 
        void SetUp() override
        {
+               ResetMountTable();
                CreateHierarchy(PARENT_DIR);
 
                /* make another directory to test the duplicate logic */
@@ -79,6 +107,8 @@ class CgroupProcessV2MntTest : public ::testing::Test {
        {
                int ret = 0;
 
+               ResetMountTable();
+
                ret = rmrf(PARENT_DIR);
                ASSERT_EQ(ret, 0);
 
@@ -117,11 +147,19 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount)
        ASSERT_STREQ(cg_mount_table[4].mount.path, ent.mnt_dir);
        ASSERT_STREQ(cg_mount_table[5].mount.path, ent.mnt_dir);
        ASSERT_STREQ(cg_mount_table[6].mount.path, ent.mnt_dir);
+       free(mnt_dir);
 }
 
 TEST_F(CgroupProcessV2MntTest, AddV2Mount_Duplicate)
 {
+       char *mnt_dir_base = strdup(PARENT_DIR);
        char *mnt_dir = strdup(PARENT2_DIR);
+       struct mntent base_ent = (struct mntent) {
+               .mnt_fsname = "cgroup2",
+               .mnt_dir = mnt_dir_base,
+               .mnt_type = "cgroup2",
+               .mnt_opts = "rw,relatime,seclabel",
+       };
        struct mntent ent = (struct mntent) {
                .mnt_fsname = "cgroup2",
                .mnt_dir = mnt_dir,
@@ -130,6 +168,9 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount_Duplicate)
        };
        int ret;
 
+       ret = cgroup_process_v2_mnt(&base_ent, &mnt_tbl_idx);
+       ASSERT_EQ(ret, 0);
+
        ret = cgroup_process_v2_mnt(&ent, &mnt_tbl_idx);
 
        ASSERT_EQ(ret, 0);
@@ -149,6 +190,8 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount_Duplicate)
        ASSERT_STREQ(cg_mount_table[4].mount.next->path, ent.mnt_dir);
        ASSERT_STREQ(cg_mount_table[5].mount.next->path, ent.mnt_dir);
        ASSERT_STREQ(cg_mount_table[6].mount.next->path, ent.mnt_dir);
+       free(mnt_dir_base);
+       free(mnt_dir);
 }
 
 /*
@@ -183,4 +226,5 @@ TEST_F(CgroupProcessV2MntTest, EmptyControllersFile)
 
        ASSERT_EQ(ret, ECGEOF);
        ASSERT_EQ(mnt_tbl_idx, 0);
+       free(mnt_dir);
 }