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).

Reply via email to