1

I connect a TCP stream socket to a given hostname and port. To get the host's IP address I use getaddrinfo() as follows

struct addrinfo hints;
struct addrinfo *result, *server;

memset(&hints, 0, sizeof(struct addrinfo)); // fill server with 0

hints.ai_family = AF_INET;   // set address family
hints.ai_protocol=0;    // set protocol type to auto
hints.ai_socktype = SOCK_STREAM;    // set type of socket to stream socket

if(getaddrinfo(HOSTNAME,PORT,&hints,&result)){
    perror("Could not resolve IP from given hostname and port (getaddrinfo)");
    freeaddrinfo(result);
    return -1;
}

if(print) printf("Connecting socket ... \n");
int connectFlag=1;
for(server=result;server!=NULL;server=server->ai_next){
    if(connect(sockfd,server->ai_addr,server->ai_addrlen)==-1){
        continue;
    }
    if(print){
        printf("Socket successfully connected\n");
    }
    break;
}
    
if(!connectFlag){
    printf("Could not connect to server %s.\n",HOSTNAME);
    close(sockfd);
    freeaddrinfo(result);
    return -1;
}

freeaddrinfo(result);

All this happens inside a function that reveivecs a parameter

int sockfd = socket(AF_INET,SOCK_STREAM,0);

from another function. Everything works out fine, the socket connects and I receive and send messages as expected.

The problem is, when I check my created binary with

valgrind --leak-check=full --trace-children=yes ./binary

I get 3313 bytes are still reachable. When resolve the host manually and connect directly using the IP I get no leaks. I replaced getaddrinfo() with the older gethostbyname() and got the exact same amount of still reachable bytes.

How can I get rid of these leaks?

Valgrind output

   % valgrind --leak-check=full --show-leak-kinds=all ./play
==16353== Memcheck, a memory error detector
==16353== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16353== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==16353== Command: ./a.out
==16353== 
==16353== 
==16353== HEAP SUMMARY:
==16353==     in use at exit: 3,313 bytes in 10 blocks
==16353==   total heap usage: 96 allocs, 86 frees, 54,234 bytes allocated
==16353== 
==16353== 64 bytes in 2 blocks are still reachable in loss record 1 of 5
==16353==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16353==    by 0x4016790: _dl_close_worker.part.0 (dl-close.c:393)
==16353==    by 0x4017029: _dl_close_worker (dl-close.c:125)
==16353==    by 0x4017029: _dl_close (dl-close.c:822)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x4F7CBAE: dlerror_run (dl-libc.c:46)
==16353==    by 0x4F7CBAE: __libc_dlclose (dl-libc.c:222)
==16353==    by 0x4FADB66: free_mem (in /lib/x86_64-linux-gnu/libc-2.23.so)
==16353==    by 0x4FAD78F: __libc_freeres (in /lib/x86_64-linux-gnu/libc-2.23.so)
==16353==    by 0x4A2868C: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so)
==16353==    by 0x4E73FAA: __run_exit_handlers (exit.c:97)
==16353==    by 0x4E74044: exit (exit.c:104)
==16353==    by 0x404162: cleanUp (in /home/a)
==16353==    by 0x401CB7: dispatch (in /home/a)
==16353== 
==16353== 71 bytes in 2 blocks are still reachable in loss record 2 of 5
==16353==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16353==    by 0x401CD89: strdup (strdup.c:42)
==16353==    by 0x401860E: _dl_load_cache_lookup (dl-cache.c:311)
==16353==    by 0x4008F98: _dl_map_object (dl-load.c:2342)
==16353==    by 0x400D9D1: openaux (dl-deps.c:63)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x400E011: _dl_map_object_deps (dl-deps.c:254)
==16353==    by 0x4015411: dl_open_worker (dl-open.c:280)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x4014BD8: _dl_open (dl-open.c:660)
==16353==    by 0x4F7C9BC: do_dlopen (dl-libc.c:87)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353== 
==16353== 71 bytes in 2 blocks are still reachable in loss record 3 of 5
==16353==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16353==    by 0x400BD23: _dl_new_object (dl-object.c:165)
==16353==    by 0x400633C: _dl_map_object_from_fd (dl-load.c:1006)
==16353==    by 0x4008A56: _dl_map_object (dl-load.c:2476)
==16353==    by 0x400D9D1: openaux (dl-deps.c:63)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x400E011: _dl_map_object_deps (dl-deps.c:254)
==16353==    by 0x4015411: dl_open_worker (dl-open.c:280)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x4014BD8: _dl_open (dl-open.c:660)
==16353==    by 0x4F7C9BC: do_dlopen (dl-libc.c:87)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353== 
==16353== 744 bytes in 2 blocks are still reachable in loss record 4 of 5
==16353==    at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16353==    by 0x4011EED: _dl_check_map_versions (dl-version.c:293)
==16353==    by 0x4015948: dl_open_worker (dl-open.c:286)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x4014BD8: _dl_open (dl-open.c:660)
==16353==    by 0x4F7C9BC: do_dlopen (dl-libc.c:87)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x4F7CA73: dlerror_run (dl-libc.c:46)
==16353==    by 0x4F7CA73: __libc_dlopen_mode (dl-libc.c:163)
==16353==    by 0x4F623BD: nss_load_library (nsswitch.c:358)
==16353==    by 0x4F630F3: __nss_lookup_function (nsswitch.c:466)
==16353==    by 0x4F630F3: __nss_next2 (nsswitch.c:242)
==16353==    by 0x4F535FA: gethostbyname2_r@@GLIBC_2.2.5 (getXXbyYY_r.c:281)
==16353==    by 0x4F259DE: gaih_inet (getaddrinfo.c:622)
==16353== 
==16353== 2,363 bytes in 2 blocks are still reachable in loss record 5 of 5
==16353==    at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16353==    by 0x400BA25: _dl_new_object (dl-object.c:75)
==16353==    by 0x400633C: _dl_map_object_from_fd (dl-load.c:1006)
==16353==    by 0x4008A56: _dl_map_object (dl-load.c:2476)
==16353==    by 0x400D9D1: openaux (dl-deps.c:63)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x400E011: _dl_map_object_deps (dl-deps.c:254)
==16353==    by 0x4015411: dl_open_worker (dl-open.c:280)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353==    by 0x4014BD8: _dl_open (dl-open.c:660)
==16353==    by 0x4F7C9BC: do_dlopen (dl-libc.c:87)
==16353==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==16353== 
==16353== LEAK SUMMARY:
==16353==    definitely lost: 0 bytes in 0 blocks
==16353==    indirectly lost: 0 bytes in 0 blocks
==16353==      possibly lost: 0 bytes in 0 blocks
==16353==    still reachable: 3,313 bytes in 10 blocks
==16353==         suppressed: 0 bytes in 0 blocks
==16353== 
==16353== For counts of detected and suppressed errors, rerun with: -v
==16353== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

If I add the valgrind option --trace-children=yes valgrind checks a child process. I did not output this because the leak is happening in this parent process.

EDIT

It turned out we were not able to reproduce the valgrind output on other hardware. On this one server getaddrinfo() produced this valgrind output as well as gethostbyname(). We did not further observed where this behaviour might come from.

Community
  • 1
  • 1
dtell
  • 2,488
  • 1
  • 14
  • 29
  • "Still reachable" does not mean a memory leak. – Kiril Kirov Jan 24 '17 at 13:40
  • I have read that before. Could you please explain what "still reachable" exactly means if not a leak? It sounds pretty much like pointers being "reachable" thus not deleted by the end of the program. – dtell Jan 24 '17 at 13:43
  • Honestly, I can't answer this, as I don't know. But the leaks are marker as "Definitely lost" and "Possibly lost", as far as I remember. And "Definitely lost" is the main thing, you must investigate and fix. – Kiril Kirov Jan 24 '17 at 13:51
  • 1
    If you show the valgrind output, someone could perhaps give you a more specific reason as to what memory is still reachable , why and where that happens. Chances are it's just the runtime library(glibc) allocating memory for a global variable once, which might be annoying , but not a leak or a problem. – nos Jan 24 '17 at 16:27

1 Answers1

1

"Still reachable" means that the program has allocated the memory AND it still has a reference to it at the time of termination. It probably means that getaddrinfo() and gethostbyname() on the first call allocates memory which is reused.

This SO-answer might also be applicable: https://stackoverflow.com/a/13230399/2696475

Community
  • 1
  • 1
FrodeTennebo
  • 531
  • 3
  • 13