This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

memory leak in res_nsend()


Hello all.

I get memory leak after using res_nsend() and I don't see a regular way to free the memory allocated in this function.
That's what I can see in resolv/res_send.c (glibc-2.3.4):
...
       for (ns = 0; ns < EXT(statp).nscount; ns++) {
           n = map[ns];
           if (EXT(statp).nsaddrs[n] == NULL)
               EXT(statp).nsaddrs[n] =
                   malloc(sizeof (struct sockaddr_in6)); /* malloc() */
           if (EXT(statp).nsaddrs[n] != NULL) {
               memcpy(EXT(statp).nsaddrs[n],
                      &statp->nsaddr_list[ns],
                      sizeof (struct sockaddr_in));
               EXT(statp).nssocks[n] = -1;
               n++;
           }
       }
...

But res_nclose() doesn't free those segments.
That's what I've found in res_thread_freeres () function (resolv/res_init.c):
...
 __res_nclose (&_res);     /* Close any VC sockets.  */

 for (int ns = 0; ns < MAXNS; ns++)
   if (_res._u._ext.nsaddrs[ns] != NULL)
     {
   free (_res._u._ext.nsaddrs[ns]);
   _res._u._ext.nsaddrs[ns] = NULL;
     }
...

Yes, copying this for fixes the memleak, but I don't consider this way as "regular".
Why should I know what exactly to free if I didn't allocate it?

Reproduce code to see the leak:
---------------------------------------
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <stdlib.h>

#ifndef DNS_T_A
#define DNS_T_A     1
#endif

typedef union {
   HEADER qb1;
   u_char qb2[65536];
} querybuf;

static void _php_dns_free_res(struct __res_state res) { /* {{{ */
   int ns;
   for (ns = 0; ns < MAXNS; ns++) {
       if (res._u._ext.nsaddrs[ns] != NULL) {
           free (res._u._ext.nsaddrs[ns]);
           res._u._ext.nsaddrs[ns] = NULL;
       }
   }
} /* }}} */


int main() { struct __res_state res; int n; querybuf buf, answer;

   memset(&res, 0, sizeof(res));
   /* initializing */
   res_ninit(&res);
   res.retrans = 5;
   res.options &= ~RES_DEFNAMES;

   /* make query */
   n = res_nmkquery(&res, QUERY, "gnu.org", C_IN, DNS_T_A, NULL, 0, NULL, buf.qb2, sizeof buf);
   if (n<0) { /* {{{ */
       res_nclose(&res);
       return 1;
   } /* }}} */

   /* send query */
   n = res_nsend(&res, buf.qb2, n, answer.qb2, sizeof answer);
   if (n<0) { /* {{{ */
       res_nclose(&res);
       return 1;
   } /* }}} */

   /* destroy res_state */
   res_nclose(&res);

   /* _php_dns_free_res(res); ! uncomment me ! */
   return 0;
}
---------------------------------------

The leak:

==12086== 84 bytes in 3 blocks are definitely lost in loss record 1 of 1
==12086==    at 0x1B9008A9: malloc (vg_replace_malloc.c:149)
==12086==    by 0x1B9296C2: __libc_res_nsend (in /lib/libresolv.so.2)
==12086==    by 0x1B92B542: __res_nsend (in /lib/libresolv.so.2)
==12086==    by 0x804864D: main (in /tmp/dns)
==12086==
==12086== LEAK SUMMARY:
==12086==    definitely lost: 84 bytes in 3 blocks.
==12086==      possibly lost: 0 bytes in 0 blocks.
==12086==    still reachable: 0 bytes in 0 blocks.
==12086==         suppressed: 0 bytes in 0 blocks.

Am I doing something wrong or is it a bug?

If this list is not for such questions, please point me to the right one.
Thanks.


--
Wbr, Antony Dovgal



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]