This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
Mtrace shows memory leak because of its own __cxa_atexit call
- From: Janito Vaqueiro Ferreira Filho <janito dot vff at gmail dot com>
- To: libc-help at sourceware dot org
- Date: Fri, 01 May 2015 15:25:35 -0300
- Subject: Mtrace shows memory leak because of its own __cxa_atexit call
- Authentication-results: sourceware.org; auth=none
Hello,
I'm a noob here, but I've found a behaviour in mtrace that I found odd.
If a certain number of atexit calls are placed before mtrace() is
called, an additional memory allocation is registered and is reported as
a leak by the auxiliary command line tool.
I found out that this happens because mtrace configures the malloc hooks
before it calls __cxa_atexit, and this function may allocate memory for
storing new function references. From what I understood by reading
stdlib.h/cxa_atexit.c, __new_exitfn allocates space when registering the
33rd function reference.
I created a simple test.c file (attached) to test it, and it seems to
work if I perform 31 calls to atexit before calling mtrace().
I attempted to "fix" the problem by moving the order of operations in
the mtrace function. I've attached a patch that only sets the hooks
after the __cxa_atexit call. It seems to have solved my problem, but I'm
unsure if there are other consequences I can't foresee.
Would this "fix" be acceptable, or would it be better if I worked around
the problem in my client program. If a workaround is better, what would
be a good approach? I'm thinking of perhaps calling mtrace() followed by
muntrace() at the start of the program once to make sure the
__cxa_atexit function is called, and consequently preventing the memory
leak from appearing in future calls of mtrace().
Thanks in advance for any feedback,
Janito
PS: To test it, I ran 'gcc test.c && ./a.out && cat /tmp/mtrace_test'
PS2: I made the patch from the 'glibc-2.21' tag, but I also tested it
with the master branch at commit 'c5a3a509dfddad86b9fef84b46a172f969cb9b4b'
#include <mcheck.h>
#include <stdlib.h>
void test_func() {
}
int main(int argc, char* argv[]) {
int count;
if (argc < 2)
count = 31;
else
count = atoi(argv[1]);
for (; count > 0; --count)
atexit(&test_func);
setenv("MALLOC_TRACE", "/tmp/mtrace_test", 0);
mtrace();
muntrace();
return 0;
}
>From a58d9a375c719a73abe882bda4f23c9b333d0664 Mon Sep 17 00:00:00 2001
From: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
Date: Fri, 1 May 2015 17:15:45 +0000
Subject: [PATCH] Move mtrace exit handler registration
---
malloc/mtrace.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index df10128..d9bca49 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -313,14 +313,6 @@ mtrace (void)
malloc_trace_buffer = mtb;
setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
fprintf (mallstream, "= Start\n");
- tr_old_free_hook = __free_hook;
- __free_hook = tr_freehook;
- tr_old_malloc_hook = __malloc_hook;
- __malloc_hook = tr_mallochook;
- tr_old_realloc_hook = __realloc_hook;
- __realloc_hook = tr_reallochook;
- tr_old_memalign_hook = __memalign_hook;
- __memalign_hook = tr_memalignhook;
#ifdef _LIBC
if (!added_atexit_handler)
{
@@ -330,6 +322,14 @@ mtrace (void)
&__dso_handle ? __dso_handle : NULL);
}
#endif
+ tr_old_free_hook = __free_hook;
+ __free_hook = tr_freehook;
+ tr_old_malloc_hook = __malloc_hook;
+ __malloc_hook = tr_mallochook;
+ tr_old_realloc_hook = __realloc_hook;
+ __realloc_hook = tr_reallochook;
+ tr_old_memalign_hook = __memalign_hook;
+ __memalign_hook = tr_memalignhook;
}
else
free (mtb);
--
1.9.1