[Bug libstdc++/87520] New: [8/9 Regression] ODR violations in std::make_shared when mixing -fno-rtti and -frtti

redi at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Thu Oct 4 13:40:00 GMT 2018


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.


More information about the Gcc-bugs mailing list