https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87520
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW Last reconfirmed| |2018-10-04 Ever confirmed|0 |1 --- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> --- A possible (partial) fix would be: --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -500,7 +500,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct _Sp_make_shared_tag { -#if !__cpp_rtti private: template<typename _Tp, _Lock_policy _Lp> friend class __shared_ptr; @@ -513,7 +512,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION alignas(type_info) static constexpr _Sp_make_shared_tag __tag; return reinterpret_cast<const type_info&>(__tag); } -#endif }; template<typename _Tp, typename _Alloc, _Lock_policy _Lp> @@ -562,16 +560,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION this->~_Sp_counted_ptr_inplace(); } - // Sneaky trick so __shared_ptr can get the managed pointer + // Sneaky trick so __shared_ptr can get the managed pointer. virtual void* - _M_get_deleter(const std::type_info& __ti) noexcept + _M_get_deleter(const std::type_info& __ti) noexcept override { -#if __cpp_rtti - if (__ti == typeid(_Sp_make_shared_tag)) -#else + // Check for the fake type_info first, so we don't try to access it + // as a real type_info object. if (&__ti == &_Sp_make_shared_tag::_S_ti()) -#endif return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr()); +#if __cpp_rtti + // Callers compiled with RTTI enabled pass this instead: + else if (__ti == typeid(_Sp_make_shared_tag)) + return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr()); +#endif return nullptr; } @@ -1323,11 +1324,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { // _M_ptr needs to point to the newly constructed object. // This relies on _Sp_counted_ptr_inplace::_M_get_deleter. -#if __cpp_rtti - void* __p = _M_refcount._M_get_deleter(typeid(__tag)); -#else void* __p = _M_refcount._M_get_deleter(_Sp_make_shared_tag::_S_ti()); -#endif _M_ptr = static_cast<_Tp*>(__p); _M_enable_shared_from_this_with(_M_ptr); } This always passes the fake _S_ti() even when rtti is enabled. Inside _M_get_deleter we check for the fake tag first, and so avoid trying to dereference it as a real typeinfo object. Old code already built with rtti could still call the function with typeid(_Sp_make_shared_tag) and so we still need to check for that (which will still fail and return a null pointer if the definition of _M_get_deleter is built without rtti). A more complete fix would be to avoid using the virtual _M_get_deleter backchannel entirely, as suggested in PR 87514 (that would need to be done in addition to the patch above, so that existing callers of the virtual function will still be able to use it).