The following code is an excerpt of my C programm to connect to a server:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PORTNUMBER 443
#define HOSTNAME "www.google.com"
int main() {
struct addrinfo hints, * res, * matchingIP;
char addrstr[99];
char port[20];
snprintf(port, sizeof(port), "%d", PORTNUMBER); // PORTNUMBER as char*
int sock;
memset( & hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_CANONNAME;
int status = getaddrinfo(HOSTNAME, port, & hints, & matchingIP); // Memory Leak occurs here?
if (status < 0) {
perror("No IP address found.");
}
for (res = matchingIP; res != NULL; res = res -> ai_next) {
sock = socket(res -> ai_family, res -> ai_socktype, res -> ai_protocol);
if (sock < 0) {
perror("No socket created.");
continue;
}
if (connect(sock, res -> ai_addr, res -> ai_addrlen) < 0) {
perror("Client not connected.");
continue;
}
break;
}
if (res == NULL) {
perror("Client could not connect.");
return EXIT_FAILURE;
}
inet_ntop(res -> ai_family, & ((struct sockaddr_in * ) res -> ai_addr) -> sin_addr, addrstr, sizeof addrstr);
printf("IPv4 address: %s (%s)\n", addrstr, res -> ai_canonname);
freeaddrinfo(matchingIP);
}
Now when I run valgrind, it shows there is "still reachable" memory, I've narrowed it down to the getaddrinfo call (the leak does not appear before). Here is the full valgrind log:
==566543== HEAP SUMMARY:
==566543== in use at exit: 3,509 bytes in 8 blocks
==566543== total heap usage: 112 allocs, 104 frees, 112,649 bytes allocated
==566543==
==566543== 38 bytes in 1 blocks are still reachable in loss record 1 of 7
==566543== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x401F5DE: strdup (strdup.c:42)
==566543== by 0x4019A91: _dl_load_cache_lookup (dl-cache.c:338)
==566543== by 0x400A989: _dl_map_object (dl-load.c:2102)
==566543== by 0x400F514: openaux (dl-deps.c:64)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x400F962: _dl_map_object_deps (dl-deps.c:248)
==566543== by 0x4015DAF: dl_open_worker (dl-open.c:571)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543==
==566543== 38 bytes in 1 blocks are still reachable in loss record 2 of 7
==566543== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x400D5B7: _dl_new_object (dl-object.c:196)
==566543== by 0x4006E96: _dl_map_object_from_fd (dl-load.c:997)
==566543== by 0x400A61A: _dl_map_object (dl-load.c:2236)
==566543== by 0x400F514: openaux (dl-deps.c:64)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x400F962: _dl_map_object_deps (dl-deps.c:248)
==566543== by 0x4015DAF: dl_open_worker (dl-open.c:571)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543==
==566543== 45 bytes in 1 blocks are still reachable in loss record 3 of 7
==566543== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x401F5DE: strdup (strdup.c:42)
==566543== by 0x4019A91: _dl_load_cache_lookup (dl-cache.c:338)
==566543== by 0x400A989: _dl_map_object (dl-load.c:2102)
==566543== by 0x4015D46: dl_open_worker (dl-open.c:513)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4A17C12: _dl_catch_error (dl-error-skeleton.c:227)
==566543== by 0x4A16C14: dlerror_run (dl-libc.c:46)
==566543== by 0x4A16C14: __libc_dlopen_mode (dl-libc.c:195)
==566543== by 0x49FA8CB: nss_load_library (nsswitch.c:359)
==566543==
==566543== 45 bytes in 1 blocks are still reachable in loss record 4 of 7
==566543== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x400D5B7: _dl_new_object (dl-object.c:196)
==566543== by 0x4006E96: _dl_map_object_from_fd (dl-load.c:997)
==566543== by 0x400A61A: _dl_map_object (dl-load.c:2236)
==566543== by 0x4015D46: dl_open_worker (dl-open.c:513)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4A17C12: _dl_catch_error (dl-error-skeleton.c:227)
==566543== by 0x4A16C14: dlerror_run (dl-libc.c:46)
==566543== by 0x4A16C14: __libc_dlopen_mode (dl-libc.c:195)
==566543== by 0x49FA8CB: nss_load_library (nsswitch.c:359)
==566543==
==566543== 936 bytes in 2 blocks are still reachable in loss record 5 of 7
==566543== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x401331C: _dl_check_map_versions (dl-version.c:274)
==566543== by 0x40160FC: dl_open_worker (dl-open.c:577)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4A17C12: _dl_catch_error (dl-error-skeleton.c:227)
==566543== by 0x4A16C14: dlerror_run (dl-libc.c:46)
==566543== by 0x4A16C14: __libc_dlopen_mode (dl-libc.c:195)
==566543== by 0x49FA8CB: nss_load_library (nsswitch.c:359)
==566543== by 0x49FB178: __nss_lookup_function (nsswitch.c:467)
==566543== by 0x49BB4BE: gaih_inet.constprop.0 (getaddrinfo.c:800)
==566543==
==566543== 1,200 bytes in 1 blocks are still reachable in loss record 6 of 7
==566543== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x400D283: _dl_new_object (dl-object.c:89)
==566543== by 0x4006E96: _dl_map_object_from_fd (dl-load.c:997)
==566543== by 0x400A61A: _dl_map_object (dl-load.c:2236)
==566543== by 0x400F514: openaux (dl-deps.c:64)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x400F962: _dl_map_object_deps (dl-deps.c:248)
==566543== by 0x4015DAF: dl_open_worker (dl-open.c:571)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543==
==566543== 1,207 bytes in 1 blocks are still reachable in loss record 7 of 7
==566543== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==566543== by 0x400D283: _dl_new_object (dl-object.c:89)
==566543== by 0x4006E96: _dl_map_object_from_fd (dl-load.c:997)
==566543== by 0x400A61A: _dl_map_object (dl-load.c:2236)
==566543== by 0x4015D46: dl_open_worker (dl-open.c:513)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4015609: _dl_open (dl-open.c:837)
==566543== by 0x4A16AE0: do_dlopen (dl-libc.c:96)
==566543== by 0x4A17B47: _dl_catch_exception (dl-error-skeleton.c:208)
==566543== by 0x4A17C12: _dl_catch_error (dl-error-skeleton.c:227)
==566543== by 0x4A16C14: dlerror_run (dl-libc.c:46)
==566543== by 0x4A16C14: __libc_dlopen_mode (dl-libc.c:195)
==566543== by 0x49FA8CB: nss_load_library (nsswitch.c:359)
==566543==
==566543== LEAK SUMMARY:
==566543== definitely lost: 0 bytes in 0 blocks
==566543== indirectly lost: 0 bytes in 0 blocks
==566543== possibly lost: 0 bytes in 0 blocks
==566543== still reachable: 3,509 bytes in 8 blocks
==566543== suppressed: 0 bytes in 0 blocks
==566543==
==566543== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I've read online several times that while "still reachable" memory leaks are memory leaks, they are not ones I should worry about. Sadly for me, it is a formal requirement that valgrind reports absolutely no memory leaks, including still reachable. Is there any chance I am able to fix it or is it the fault of the library? If the latter - what are suitable alternatives? As far as I am are the host runs using IPv6 - perhaps that's relevant.
Edit: The project is compiled with the -std=c99 flag and defines the posix C source as #define _POSIX_C_SOURCE 200809L. The valgrind flags are valgrind --leak-check=full --show-leak-kinds=all --trace-children=yes --log-file=log.txt --track-origins=yes -s and I'm developing on Ubuntu 20.04.6 LTS
Another edit: Minimal reproducible example
It's not really a fault, but as you noted (and was also mentioned in the comments)
libcdecided it needs to bind tolibnss. There are at least a couple of ways to confirm that:LD_DEBUG=bindings(e.g.,LD_DEBUG=bindings ./program)getchar()to pause your program before exiting and examine/proc/<pid>/maps.Unfortunatelly, there's no reliable or portable way to
dl_close()that I'm aware of.The best alternative is to provide
valgrindwith a suppressions file which will make it ignore specific allocations/leaks/reachable blocks.You can generate one specifically for this case by running
valgrindas you did but adding the option--gen-suppressions=yes.