https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88782

--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Author: redi
Date: Mon Jan 21 13:16:25 2019
New Revision: 268114

URL: https://gcc.gnu.org/viewcvs?rev=268114&root=gcc&view=rev
Log:
PR libstdc++/88782 avoid ODR problems in std::make_shared

The old version of _Sp_counted_ptr_inplace::_M_get_deleter (up to GCC
8.2.0) expects to be passed a real std::typeinfo object, so mixing that
with the new definition of the __shared_ptr constructor (which always
passes the fake tag) leads to accessing the fake object as a real
std::typeinfo. Instead of trying to make it safe to mix the old and new
definitions, just stop using that function. By passing a reference to
__shared_ptr::_M_ptr to the __shared_count constructor it can be set
directly, without needing to obtain the pointer via the _M_get_deleter
back-channel. This avoids a virtual dispatch (which fixes PR 87514).

This means that code built against new libstdc++ headers doesn't use
_M_get_deleter at all, and so make_shared works the same whether RTTI is
enabled or not.

Unlike on trunk, where _M_get_deleter calls a new library function that
can detect the real type_info object even when RTTI is disabled, this
commit for gcc-8-branch cannot add a new symbol to the shared library.
That means _M_get_deleter still returns null if compiled without RTTI
and it gets called from a translation unit that was compiled with RTTI.

If linking to objects built against older versions of libstdc++ then if
all objects use -frtti or all use -fno-rtti, then the caller of
_M_get_deleter and the definition of _M_get_deleter will be consistent
and it will work. If mixing -frtti with -fno-rtti it can still fail if
the linker picks an old definition of _M_get_deleter and an old
__shared_ptr constructor that are incompatible. In that case some or all
objects might need to be recompiled (or just relinked in a different
order).

Backport from mainline
2019-01-18  Jonathan Wakely  <jwak...@redhat.com>

        PR libstdc++/87514
        PR libstdc++/87520
        PR libstdc++/88782
        * config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Export new symbol.
        * include/bits/shared_ptr.h
        (shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...))
        (allocate_shared): Change to use new tag type.
        * include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_eq):
        Declare new member function.
        (_Sp_alloc_shared_tag): Define new type.
        (_Sp_counted_ptr_inplace): Declare __shared_count<_Lp> as a friend.
        (_Sp_counted_ptr_inplace::_M_get_deleter) [!__cpp_rtti]: Use
        _Sp_make_shared_tag::_S_eq to check type_info.
        (__shared_count(Ptr, Deleter),__shared_count(Ptr, Deleter, Alloc)):
        Constrain to prevent being called with _Sp_alloc_shared_tag.
        (__shared_count(_Sp_make_shared_tag, const _Alloc&, Args&&...)):
        Replace constructor with ...
        (__shared_count(Tp*&, _Sp_alloc_shared_tag<_Alloc>, Args&&...)): Use
        reference parameter so address of the new object can be returned to
        the caller. Obtain the allocator from the tag type.
        (__shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...)): Replace
        constructor with ...
        (__shared_ptr(_Sp_alloc_shared_tag<Alloc>, Args&&...)): Pass _M_ptr
        to the __shared_count constructor.
        (__allocate_shared): Change to use new tag type.
        * src/c++11/shared_ptr.cc (_Sp_make_shared_tag::_S_eq): Define.

Modified:
    branches/gcc-8-branch/libstdc++-v3/ChangeLog
    branches/gcc-8-branch/libstdc++-v3/include/bits/shared_ptr.h
    branches/gcc-8-branch/libstdc++-v3/include/bits/shared_ptr_base.h

Reply via email to