Bug 57914 - Memory leak in __cxa_thread_atexit when using thread_local
Summary: Memory leak in __cxa_thread_atexit when using thread_local
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.8.1
: P3 normal
Target Milestone: 4.8.2
Assignee: Jason Merrill
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-07-16 21:12 UTC by Stephen Croll
Modified: 2013-07-28 02:33 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-07-22 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Stephen Croll 2013-07-16 21:12:53 UTC
Valgrind is reporting leaked blocks in __cxa_thread_atexit,
apparently one per thread, in the following code:

#include <iostream>
#include <thread>

struct Foo
{
    ~Foo() 
    { 
    }

    void 
    hello_world() 
    { 
        std::cout << __PRETTY_FUNCTION__ << '\n'; 
    }
};

thread_local Foo foo;

void
hello_world_thread()
{
    foo.hello_world();
}

int main()
{
    for ( int i = 0; i < 10; ++i )
    {
        std::thread thread( hello_world_thread );
        thread.join();
    }
}


Program compiled as follows:

$ g++ -std=gnu++11 -Og -g3 -Wall -Wextra -fno-omit-frame-pointer thread_local_bug.cc


GCC info:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/localhome/scroll/tools/2/x86_64/stow/gcc-4.8.1/libexec/gcc/x86_64-unknown-linux-gnu/4.8.1/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-4.8.1/configure --prefix=/localhome/scroll/tools/2/x86_64/stow/gcc-4.8.1 --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-cxx-flags='-fno-omit-frame-pointer -g3' --enable-languages=c,c++ --enable-libstdcxx-time=rt --enable-checking=release --enable-build-with-cxx --disable-werror --disable-multilib --disable-bootstrap --with-system-zlib
Thread model: posix
gcc version 4.8.1 (GCC) 


Valgrind version:

$ valgrind --version
valgrind-3.8.1


Valgrind command line:

$ valgrind --leak-check=full --verbose ./a.out > /dev/null


Tail-end of valgrind output:

==7102== HEAP SUMMARY:
==7102==     in use at exit: 240 bytes in 10 blocks
==7102==   total heap usage: 21 allocs, 11 frees, 1,104 bytes allocated
==7102== 
==7102== Searching for pointers to 10 not-freed blocks
==7102== Checked 216,120 bytes
==7102== 
==7102== 240 bytes in 10 blocks are definitely lost in loss record 1 of 1
==7102==    at 0x4C29969: operator new(unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:329)
==7102==    by 0x4E8E53E: __cxa_thread_atexit (atexit_thread.cc:119)
==7102==    by 0x400F69: _ZTH3foo (thread_local_bug.cc:17)
==7102==    by 0x400F79: hello_world_thread() (thread_local_bug.cc:17)
==7102==    by 0x401006: std::thread::_Impl<std::_Bind_simple<void (*())()> >::_M_run() (functional:1732)
==7102==    by 0x4EE4830: execute_native_thread_routine (thread.cc:84)
==7102==    by 0x5A10E99: start_thread (pthread_create.c:308)
==7102==    by 0x573DCCC: clone (clone.S:112)
==7102== 
==7102== LEAK SUMMARY:
==7102==    definitely lost: 240 bytes in 10 blocks
==7102==    indirectly lost: 0 bytes in 0 blocks
==7102==      possibly lost: 0 bytes in 0 blocks
==7102==    still reachable: 0 bytes in 0 blocks
==7102==         suppressed: 0 bytes in 0 blocks
==7102== 
==7102== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
--7102-- 
--7102-- used_suppression:      2 dl-hack3-cond-1
==7102== 
==7102== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)


Notes:

- If you change the number of threads created, the number of leaked
  blocks matches the number of threads.

- From the valgrind stacktrace, thread_local_bug.cc:17 is the line:
  'thread_local Foo foo;'
Comment 1 Jonathan Wakely 2013-07-21 20:03:20 UTC
I think Jason is the best person to look at this.
Comment 2 Jason Merrill 2013-07-22 02:36:24 UTC
Yes, we weren't freeing the objects allocated to track the cleanups for foo.  That doesn't seem like an important leak, but I'll fix it.
Comment 3 Paolo Carlini 2013-07-25 00:26:11 UTC
This is fixed for 4.9.0.
Comment 4 Jason Merrill 2013-07-28 02:33:44 UTC
And 4.8.2.