https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87520
Bug ID: 87520
Summary: [8/9 Regression] ODR violations in std::make_shared
when mixing -fno-rtti and -frtti
Product: gcc
Version: 8.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: redi at gcc dot gnu.org
Target Milestone: ---
cat > main.cc << EOT
#include <memory>
extern int f();
// For the purposes of this demo, force a non-weak definition of
// _Sp_counted_ptr_inplace::_M_get_deleter(const type_info&) to be emitted
// in this translation unit:
template class
std::_Sp_counted_ptr_inplace<int, std::allocator<int>, std::_S_atomic>;
int main()
{
return f();
}
EOT
cat > sp.cc << EOT
#include <memory>
int f()
{
return *std::make_shared<int>();
}
EOT
g++ -fno-rtti main.cc -c -g
g++ -frtti sp.cc -c -g
g++ main.o sp.o
./a.out
This crashes:
Segmentation fault (core dumped)
The problem is that the definition of _Sp_counter_ptr_inplace::_M_get_deleter
that the linker chooses was compiled with -fno-rtti but the caller was compiled
with -frtti. The caller passes typeid(_Sp_make_shared_tag) which does not match
the expected value in _M_get_deleter, so a null pointer is returned. That
leaves the new shared_ptr holding a null pointer, so dereferencing it in f()
crashes.
This crash happens for all versions.
A nastier failure happens with gcc-8 and trunk if we swap which object is built
with RTTI and which without:
g++ -frtti main.cc -c -g
g++ -fno-rtti sp.cc -c -g
g++ main.o sp.o
./a.out
This crashes earlier, during construction of the shared_ptr:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004008cb in std::type_info::operator== (this=0x401700
<std::_Sp_make_shared_tag::_S_ti()::__tag>, __arg=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/typeinfo:123
(gdb) bt
#0 0x00000000004008cb in std::type_info::operator== (this=0x401700
<std::_Sp_make_shared_tag::_S_ti()::__tag>, __arg=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/typeinfo:123
#1 0x0000000000400a31 in std::_Sp_counted_ptr_inplace<int,
std::allocator<int>, (__gnu_cxx::_Lock_policy)2>::_M_get_deleter
(this=0x615e70, type_info node=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/bits/shared_ptr_base.h:569
#2 0x0000000000401264 in
std::__shared_count<(__gnu_cxx::_Lock_policy)2>::_M_get_deleter
(this=0x7fffffffd858, type_info node=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/bits/shared_ptr_base.h:749
#3 0x00000000004010ba in std::__shared_ptr<int,
(__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<int>>(std::_Sp_make_shared_tag,
std::allocator<int> const&) (this=0x7fffffffd850, __tag=..., __a=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/bits/shared_ptr_base.h:1329
#4 0x0000000000401055 in
std::shared_ptr<int>::shared_ptr<std::allocator<int>>(std::_Sp_make_shared_tag,
std::allocator<int> const&) (this=0x7fffffffd850, __tag=..., __a=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/bits/shared_ptr.h:360
#5 0x0000000000400f8a in std::allocate_shared<int,
std::allocator<int>>(std::allocator<int> const&) (__a=...) at
/home/jwakely/gcc/8/include/c++/8.2.1/bits/shared_ptr.h:707
#6 0x0000000000400ed5 in std::make_shared<int> () at
/home/jwakely/gcc/8/include/c++/8.2.1/bits/shared_ptr.h:723
#7 0x0000000000400d80 in f () at sp.cc:5
#8 0x000000000040089b in main () at main.cc:13
This is due to the fix for PR 80285. The __shared_ptr constructor is built
without RTTI so calls _M_get_deleter(_Sp_make_shared_tag::_S_ti()). The
definition of _M_get_deleter is built with RTTI so expects a real typeinfo
object. When accessing the fake _S_ti() typeinfo object we crash, because it's
an invalid reference that isn't bound to a real typeinfo.