This code crashes in the destructor of 'map':
#include <thread>
#include <unordered_map>
#include <vector>
#include <sstream>
#define print(msg) {std::stringstream ss; ss << std::this_thread::get_id() << ": " << msg; printf("%s\n", ss.str().c_str());}
struct A
{
std::unordered_map<int, int> map;
};
A &getA()
{
static thread_local A inst;
return inst;
}
int main()
{
std::vector<std::thread> threads;
for (size_t i = 0; i < std::thread::hardware_concurrency() * 4; i++)
{
threads.emplace_back([]()
{
print(getA().map.size());
});
}
for (auto &thread : threads)
thread.join();
return 0;
}
The correct output would be http://coliru.stacked-crooked.com/a/e4e4c21b32719ca9.
Link correction: http://coliru.stacked-crooked.com/a/e4e4c21b32719ca9
It's fine with
gcc version 7.3.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)with compiler flagsg++ -mthreads test.cpp. To use C++ threads, you need posix thread model GCC with-mthreadsflag.I would appreciate if this gets reopened, this is a serious problem which got confirmed after a short talk on #mingw-w64 irc. It seems to concern every thread_local object with a non-trivial destructor. If I understood it right, the memory of the thread_local object gets freed before the destructor gets called. For a compiler as significant as mingw-w64, this is a serious issue.
Last edit: Martin Stumpf 2018-04-27
done
thanks :)
I'm sorry to nag, but I'm very unsatisfied with that response.
First of all, 'g++ -mthreads test.ccp' doesn't even compile the code, it's 'g++ -mthreads -std=c++11 test.cpp'.
This specific source file does not seem to crash with -O3, please verify that you didn't use optimization. (Seems to mess up the timing required for this bug to show)
It did happen to us with -O3 in more complex scenarios, though.
Second, this is not at all invalid, and if it didn't crash for you in your setup doesn't mean this bug doesn't exist. As we weren't able to find a Win10 configuration where this code does not crash, it should be fairly simple to reproduce. It currently crashes on all our production machines.
We confirmed this bug on Windows 10 on both the latest version on https://sourceforge.net/projects/mingw-w64/ and on the up-to-date version of winbuilds.
To make sure, I reinstalled the newest version of MinGW-w64 builds from sourceforge.
This is the command line output:
Then, crash. The computer running is a Lenovo T450s with Windows 10 Pro Version 10.0.16299 Build 16299. It's a quadcore, the numbers should therefore count to 16. That said, it's not computer specific but happens on all the machines I tested it on.
Try to build with
g++ -std=c++11 -mthreads -g -O0 test.cpp, and run in gdb to get some stacktrace.A related bug "#527 thread_local stl object's destructor causing crash": https://sourceforge.net/p/mingw-w64/bugs/527/
This is a duplicate of 527. The crash will not happen on x64 where
__stdcalland__cdeclare virtually identical. The crash will only be observed on x86.Last edit: LIU Hao 2018-05-02
This seems different with 527, and both can reproduced in my Lenovo desktop with AMD Athlon II X64 + Windows 10 Pro 1083 (10.0.17134.1) x64.
backtrace for 727 using
backtrace for 527 using
backtrace for 527 using
Last edit: Zufu Liu 2018-05-05
All of the machines I confirmed this bug on were x64.
Last edit: Martin Stumpf 2018-05-09
There are at least two bugs related to
thread_localon mingw-w64. Other than the calling convention one on i686, destructors ofthread_localobjects might be invoked AFTER those ofstaticobjects, which violates the c++ standard and results in crashes. There is already a report for it. Please check whether this is the case here.I also see a thread_local crash affecting mingw-w64 that might be a duplicate:
https://gist.github.com/rprichard/d0fad2161a3e2b7474b561d040ec5b40
I think this is what's going on:
__cxa_thread_atexitfunction in libsupc++ uses a pthread key to call the C++ destructors (i.e. pass a destructor topthread_key_create).__thread/thread_localvariables is allocated with emutls (in libgcc), which uses a different pthread key to callemutls_destroy.emutls_destroycan be called before the__cxa_thread_atexitdestructors, and if that happens, the destructors access freed memory.The same problem affects some (older) Android configurations: https://github.com/android-ndk/ndk/issues/687