This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
memory leak in res_nsend()
- From: Antony Dovgal <tony2001 at phpclub dot net>
- To: libc-alpha at sources dot redhat dot com
- Date: Mon, 24 Oct 2005 14:28:03 +0400
- Subject: 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