http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58142
Bug ID: 58142 Summary: _pthread_tsd_cleanup called before destructors are called Product: gcc Version: 4.8.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: soonhok at cs dot cmu.edu Created attachment 30638 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=30638&action=edit preprocessed input file It seems when a thread is finished, its thread cleanup routine is called before destructors of TLS(Thread Local Storage) variables are called and it causes (possible) segmentation faults. I provided a simplified small program which reproduces the behavior. Even if it doesn't generate a segmentation fault, running valgrind over it indicates the same problem is going on in run-time. This problem happens only on OSX. When I tried the same C++ code on Ubuntu12.04 with g++-4.8.1. There was no problem. I also tried with clang++-3.3 on OSX. There was no problem either. 1. The exact version of GCC: gcc-4.8.1 2. the system type: OSX 10.8.4, Darwin air 12.4.0 Darwin Kernel Version 12.4.0 3. the options given when GCC was configured/built: g++-4.8 -std=c++11 thread.cpp -O thread 4. the complete command line that triggers the bug; valgrind thread 5. the compiler output (error messages, warnings, etc.); and the preprocessed file (*.i*) that triggers the bug, generated by adding -save-temps to the complete compilation command, or, in the case of a bug report for the GNAT front end, a complete set of source files (see below). Preprocessed file is attached. Here is the original source code (much shorter): ====================================================================== #include <thread> #include <iostream> #include <mutex> #include <vector> static void foo() { static thread_local std::vector<int> v(1024); if (v.size() != 1024) { std::cerr << "Error\n"; exit(1); } } static void tst1() { unsigned n = 5; for (unsigned i = 0; i < n; i++) { std::thread t([](){ foo(); }); t.join(); } } int main() { tst1(); } ====================================================================== The following is the output of valgrind: ... ==18408== Invalid read of size 8 ==18408== at 0x1000021B3: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (in ./a.out) ==18408== by 0x100002054: std::vector<int, std::allocator<int> >::~vector() (in ./a.out) ==18408== by 0xB9F5: (anonymous namespace)::run(void*) (in /usr/local/lib/libstdc++.6.dylib) ==18408== by 0x29CA01: _pthread_exit (in /usr/lib/system/libsystem_c.dylib) ==18408== by 0x29C7AC: _pthread_start (in /usr/lib/system/libsystem_c.dylib) ==18408== by 0x2891E0: thread_start (in /usr/lib/system/libsystem_c.dylib) ==18408== Address 0x1000257a8 is 8 bytes inside a block of size 32 free'd ==18408== at 0x5632: free (in /usr/local/Cellar/valgrind/3.8.1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) ==18408== by 0x1CAA12: emutls_destroy (in /usr/local/lib/libgcc_s.1.dylib) ==18408== by 0x101: ??? ==18408== by 0xB0080E9F: ??? ==18408== by 0xB008186F: ??? ==18408== by 0x2A34DF: _pthread_tsd_cleanup (in /usr/lib/system/libsystem_c.dylib) ==18408== by 0xB008105F: ??? ...