PR 52064 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52604) added a guard assignment to libstdc++-v3/src/c++98/mt_allocator.cc (_M_thread_freelist = 0), so that attempts to use the freelist after it had been destroyed would not access invalid memory. This resolved issues with global-scope STL containers that used mt_allocator being destroyed after the mt_allocator freelist was destroyed.
_M_thread_freelist = 0;
The setting of the _M_thread_freelist member can validly be optimized away, because accessing the object after its destructor has run is undefined behavior, and the _M_thread_freelist assignment can't be detected other than by doing that. Since PR 52064 was resolved in 2012, it appears that gcc has become smarter about optimizing this case, and the guard assignment no longer is compiled. I get this assembly:
0x7ffff055d4f0 <(anonymous namespace)::__freelist::~__freelist()>:
+ 0: cmpq $0x0,0x8(%rdi)
+ 5: je 0x7ffff055d510 <(anonymous namespace)::__freelist::~__freelist()+32>
+ 7: push %rbx
+ 8: mov %rdi,%rbx
+11: mov 0x18(%rdi),%edi
+14: callq 0x7ffff054d670 <pthread_key_delete@plt>
+19: mov 0x8(%rbx),%rdi
+23: pop %rbx
+24: jmpq 0x7ffff054b9f0 <_ZdlPv@plt>
+29: nopl (%rax)
+32: repz retq
It does seem like the existing code is taking advantage of undefined behavior, so maybe a larger change is in order, but changing the assignment to happen through a volatile pointer - const_cast<_Thread_record *volatile &>(_M_thread_freelist) = 0 - resolves the issue.
Correction: the original bug was PR 52604, not PR 52064.
Duplicate then (52604 is not marked fixed anyway).
*** This bug has been marked as a duplicate of bug 52604 ***
I would like to deprecate mt_allocator, I don't recommend using it.