From: Kamalesh Babulal Date: Sat, 21 Feb 2026 02:48:30 +0000 (+0530) Subject: tools/cgget: free controller tokens and revert cgroup on -g failure X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=5d259f2eba792035cfa691f32a608d1d644baec4;p=thirdparty%2Flibcgroup.git tools/cgget: free controller tokens and revert cgroup on -g failure AddressSanitizer reported two 8-byte leaks when handling cgget -g controller:: Direct leak of 8 byte(s) in 1 object(s) allocated from: #0 0x... in __interceptor_realloc #1 split_controllers (/src/tools/cgget.c:257) Direct leak of 8 byte(s) in 1 object(s) allocated from: #0 0x... in __interceptor_realloc #1 create_cgrp (/src/tools/cgget.c:76) split_controllers() grew the controller array with realloc()/strdup() but on failure it leaked every already-duplicated token, and the caller never freed the temporary array even on success. parse_g_flag_with_colon() also pushed a new struct cgroup onto the list and left it behind whenever a later step bailed out, so the cgroup object stayed allocated. The helper now frees the duplicated controller tokens on error, releases the scratch array after use, and if parsing fails it frees the freshly appended cgroup and drops the length so the caller ignores it. With these changes the ASan leak report disappears. Signed-off-by: Kamalesh Babulal Signed-off-by: Tom Hromatka --- diff --git a/src/tools/cgget.c b/src/tools/cgget.c index 2bf73fc3..40e37f74 100644 --- a/src/tools/cgget.c +++ b/src/tools/cgget.c @@ -242,7 +242,7 @@ static int split_cgroup_name(const char * const ctrl_str, char *cgrp_name) static int split_controllers(const char * const in, char **ctrl[], int * const ctrl_len) { char *copy, *tok, *colon, *saveptr = NULL; - int ret = 0; + int i, ret = 0; char **tmp; copy = strdup(in); @@ -275,6 +275,14 @@ out: if (saveptr) free(saveptr); + if (ret) { + for (i = 0; i < *ctrl_len; i++) + free((*ctrl)[i]); + free(*ctrl); + *ctrl = NULL; + *ctrl_len = 0; + } + return ret; } @@ -284,9 +292,11 @@ static int parse_g_flag_with_colon(struct cgroup **cgrp_list[], int * const cgrp struct cgroup_controller *cgc; struct cgroup *cgrp = NULL; char **controllers = NULL; - int controllers_len = 0; + int orig_len, controllers_len = 0; int i, ret = 0; + orig_len = *cgrp_list_len; + ret = create_cgrp(cgrp_list, cgrp_list_len); if (ret) goto out; @@ -316,6 +326,14 @@ static int parse_g_flag_with_colon(struct cgroup **cgrp_list[], int * const cgrp out: for (i = 0; i < controllers_len; i++) free(controllers[i]); + free(controllers); + + if (ret && *cgrp_list_len > orig_len) { + /* Remove the cgroup we just appended */ + cgroup_free(&(*cgrp_list)[(*cgrp_list_len) - 1]); + (*cgrp_list)[(*cgrp_list_len) - 1] = NULL; + (*cgrp_list_len)--; + } return ret; }