I'm trying to retrieve a linux group with some basic C code, but I encounter memory leaks with both getgrnam and getgrnam_r. The memory leaks only occurs when the linux group is missing in /etc/group
.
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
static char* group_name = "dummy";
static void test_getgrnam_r(void) {
struct group grp;
struct group* group = NULL;
int bufsize = 0;
int retval = -1;
char* buf = NULL;
bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
if(bufsize == -1) {
bufsize = 16384;
}
buf = calloc(1, bufsize);
retval = getgrnam_r(group_name, &grp, buf, bufsize, &group);
printf("retval = %d\n", retval);
free(buf);
free(group);
}
static void test_getgrnam(void) {
struct group* group = getgrnam(group_name);
}
int main(void) {
test_getgrnam();
//test_getgrnam_r();
}
This code can be compiled with a simple gcc command:
gcc main.c -o out
and it can be run with valgrind to show the memory leaks:
valgrind --leak-check=full --show-leak-kinds=all ./out
==2255356== Memcheck, a memory error detector
==2255356== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2255356== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==2255356== Command: ./out
==2255356==
==2255356==
==2255356== HEAP SUMMARY:
==2255356== in use at exit: 5,177 bytes in 13 blocks
==2255356== total heap usage: 77 allocs, 64 frees, 19,669 bytes allocated
==2255356==
==2255356== 46 bytes in 1 blocks are still reachable in loss record 1 of 8
==2255356== at 0x483877F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x401C26A: strdup (strdup.c:42)
==2255356== by 0x40172FB: _dl_load_cache_lookup (dl-cache.c:338)
==2255356== by 0x4009776: _dl_map_object (dl-load.c:2102)
==2255356== by 0x4013D41: dl_open_worker (dl-open.c:513)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x4987C0E: _dl_catch_error (dl-error-skeleton.c:227)
==2255356== by 0x49870A6: dlerror_run (dl-libc.c:46)
==2255356== by 0x4987135: __libc_dlopen_mode (dl-libc.c:195)
==2255356==
==2255356== 46 bytes in 1 blocks are still reachable in loss record 2 of 8
==2255356== at 0x483877F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x400BFB7: _dl_new_object (dl-object.c:196)
==2255356== by 0x4007255: _dl_map_object_from_fd (dl-load.c:997)
==2255356== by 0x4009274: _dl_map_object (dl-load.c:2236)
==2255356== by 0x4013D41: dl_open_worker (dl-open.c:513)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x4987C0E: _dl_catch_error (dl-error-skeleton.c:227)
==2255356== by 0x49870A6: dlerror_run (dl-libc.c:46)
==2255356== by 0x4987135: __libc_dlopen_mode (dl-libc.c:195)
==2255356==
==2255356== 71 bytes in 2 blocks are still reachable in loss record 4 of 8
==2255356== at 0x483877F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x401C26A: strdup (strdup.c:42)
==2255356== by 0x40172FB: _dl_load_cache_lookup (dl-cache.c:338)
==2255356== by 0x4009776: _dl_map_object (dl-load.c:2102)
==2255356== by 0x400DDC0: openaux (dl-deps.c:64)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x400E138: _dl_map_object_deps (dl-deps.c:248)
==2255356== by 0x4013DAA: dl_open_worker (dl-open.c:571)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356==
==2255356== 71 bytes in 2 blocks are still reachable in loss record 5 of 8
==2255356== at 0x483877F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x400BFB7: _dl_new_object (dl-object.c:196)
==2255356== by 0x4007255: _dl_map_object_from_fd (dl-load.c:997)
==2255356== by 0x4009274: _dl_map_object (dl-load.c:2236)
==2255356== by 0x400DDC0: openaux (dl-deps.c:64)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x400E138: _dl_map_object_deps (dl-deps.c:248)
==2255356== by 0x4013DAA: dl_open_worker (dl-open.c:571)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356==
==2255356== 1,204 bytes in 1 blocks are still reachable in loss record 6 of 8
==2255356== at 0x483AB65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x400BCDF: _dl_new_object (dl-object.c:89)
==2255356== by 0x4007255: _dl_map_object_from_fd (dl-load.c:997)
==2255356== by 0x4009274: _dl_map_object (dl-load.c:2236)
==2255356== by 0x4013D41: dl_open_worker (dl-open.c:513)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x4987C0E: _dl_catch_error (dl-error-skeleton.c:227)
==2255356== by 0x49870A6: dlerror_run (dl-libc.c:46)
==2255356== by 0x4987135: __libc_dlopen_mode (dl-libc.c:195)
==2255356==
==2255356== 1,296 bytes in 3 blocks are still reachable in loss record 7 of 8
==2255356== at 0x483AB65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x40116B6: _dl_check_map_versions (dl-version.c:274)
==2255356== by 0x4013DF5: dl_open_worker (dl-open.c:577)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x4987C0E: _dl_catch_error (dl-error-skeleton.c:227)
==2255356== by 0x49870A6: dlerror_run (dl-libc.c:46)
==2255356== by 0x4987135: __libc_dlopen_mode (dl-libc.c:195)
==2255356== by 0x496F355: nss_load_library (nsswitch.c:359)
==2255356== by 0x496FBE8: __nss_lookup_function (nsswitch.c:467)
==2255356==
==2255356== 2,395 bytes in 2 blocks are still reachable in loss record 8 of 8
==2255356== at 0x483AB65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2255356== by 0x400BCDF: _dl_new_object (dl-object.c:89)
==2255356== by 0x4007255: _dl_map_object_from_fd (dl-load.c:997)
==2255356== by 0x4009274: _dl_map_object (dl-load.c:2236)
==2255356== by 0x400DDC0: openaux (dl-deps.c:64)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x400E138: _dl_map_object_deps (dl-deps.c:248)
==2255356== by 0x4013DAA: dl_open_worker (dl-open.c:571)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356== by 0x40138F9: _dl_open (dl-open.c:837)
==2255356== by 0x4986FCC: do_dlopen (dl-libc.c:96)
==2255356== by 0x4987B4F: _dl_catch_exception (dl-error-skeleton.c:208)
==2255356==
==2255356== LEAK SUMMARY:
==2255356== definitely lost: 0 bytes in 0 blocks
==2255356== indirectly lost: 0 bytes in 0 blocks
==2255356== possibly lost: 0 bytes in 0 blocks
==2255356== still reachable: 5,129 bytes in 12 blocks
==2255356== suppressed: 48 bytes in 1 blocks
==2255356==
==2255356== For lists of detected and suppressed errors, rerun with: -s
==2255356== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I have found some similar posts, but none of them seem to have a solution for this issue.
Some of them suggest using
extern void __libc_freeres (void);
But calling this function also doesn't seem to help. Based on the valgrind documentation, I think this function is already called by default when running valgrind.
--run-libc-freeres=<yes|no> [default: yes]
https://valgrind.org/docs/manual/manual-core.html
Does this mean I am stuck with a memory leak or is there a solution I have not found yet? Please let me know if I can provide extra information. I tried to keep my example as simple as possible.