http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57914

            Bug ID: 57914
           Summary: Memory leak in __cxa_thread_atexit when using
                    thread_local
           Product: gcc
           Version: 4.8.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: stephen.d.croll at gmail dot com

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;'

Reply via email to