This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/68200] New: g++ 5.2 optimizes out pointer assignment in libstdc++ mt_allocator freelist destructor, causing crash at global-dtor time
- From: "oremanj at mit dot edu" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 03 Nov 2015 17:15:54 +0000
- Subject: [Bug libstdc++/68200] New: g++ 5.2 optimizes out pointer assignment in libstdc++ mt_allocator freelist destructor, causing crash at global-dtor time
- Auto-submitted: auto-generated
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68200
Bug ID: 68200
Summary: g++ 5.2 optimizes out pointer assignment in libstdc++
mt_allocator freelist destructor, causing crash at
global-dtor time
Product: gcc
Version: 5.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: oremanj at mit dot edu
Target Milestone: ---
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.
~__freelist()
{
if (_M_thread_freelist_array)
{
__gthread_key_delete(_M_key);
::operator delete(static_cast<void*>(_M_thread_freelist_array));
_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.