Search code examples
c++memory-leaksg++static-librariesmtrace

g++ -static causes memory leak (reported by mtrace)


So I'm having a strange problem that I'm hoping someone can shed some light on... I have the following code:

#include <unistd.h>
#include <mcheck.h>
#include <pthread.h>

static void *run(void *args)
{
  sleep(1);
  return NULL;
}

int main()
{
  mtrace();
  pthread_t thread;
  pthread_create(&thread, NULL, run, NULL);
  pthread_join(thread, NULL);

  return 0;
}

And I compile I've compiled it in these 2 ways:

g++ -static program.cpp -lpthread

and

g++ program.cpp -ltpthread

When I look at the mtrace's output (mem.out in my case)

I see the following when i use the -static option, mtrace reports:

Memory Not freed:
__________________
   Address      Size   Caller
   0x085ac350   0x88   program.cpp:0

But when I exclude the -static option, mtrace reports the glorious:

No memory leaks.

So any ideas as to whats going on here?


Solution

  • Here's a recipe for reproducing this on my regular desktop Linux system (FC-17):

    #include <mcheck.h>
    #include <pthread.h>
    
    extern "C" { static void *run(void *) { return 0; } }
    
    int main() {
      mtrace();
      pthread_t thread;
      pthread_create(&thread, 0, run, 0);
      pthread_join(thread, 0);
      return 0;
    }
    

    Compiled with g++ -g -static -pthread. This is how I executed it to get the mtrace error:

    $ MALLOC_TRACE=mt.txt mtrace ./a.out mt.txt
    
    Memory not freed:
    -----------------
               Address     Size     Caller
    0x00000000011a9c90    0x110  at 0x43d7f9
    

    I have a 64 bit system, so the size doesn't match. When I disassemble the address in gdb, it gives this:

    (gdb) disass 0x43d7f9
    Dump of assembler code for function _dl_allocate_tls:
       0x000000000043d7c0 <+0>:     mov    %rbx,-0x20(%rsp)
       0x000000000043d7c5 <+5>:     mov    %rbp,-0x18(%rsp)
    ...
       0x000000000043d7f4 <+52>:    callq  0x428150 <calloc>
       0x000000000043d7f9 <+57>:    test   %rax,%rax
       0x000000000043d7fc <+60>:    je     0x43d8e0 <_dl_allocate_tls+288>
    ...
    

    So it looks like some thread local storage was allocated for the thread. It seems like a one time allocation per thread, because there are no additional allocations when I added a pthread_create call after the join, while there was one when I added it before the join. The _dl_allocate_tls suggests this is normally a functioned called during dynamic linking, but it seems it is being called during thread stack initialization. A grep through the glibc code shows it is being called in allocate_stack.c.

    There does seem to be corresponding calls to _dl_deallocate_tls in glibc, so I think this error is harmless. valgrind does not pick up any memory leaks.