aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2018-11-22 13:42:39 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2018-11-22 13:42:39 +0000
commita942dfca6a19d79a7c849f1c00a5da61e89600a8 (patch)
tree53f44010fde467a88e1b5a6e6abde1770d7ca576
parenta8589077793df1bfc915bd4f341ae9f6f127291b (diff)
downloadgcc-a942dfca6a19d79a7c849f1c00a5da61e89600a8.zip
gcc-a942dfca6a19d79a7c849f1c00a5da61e89600a8.tar.gz
gcc-a942dfca6a19d79a7c849f1c00a5da61e89600a8.tar.bz2
PR libstdc++/87520 Always pass type-punned type_info reference
The implementations of std::make_shared for -frtti and -fno-rtti are not compatible, because they pass different arguments to _Sp_counted_ptr_inplace::_M_get_deleter and so can't interoperate. Either the argument doesn't match the expected value, and so the shared_ptr::_M_ptr member is never set, or the type-punned reference is treated as a real std::type_info object and gets dereferenced. This patch removes the differences between -frtti and -fno-rtti, so that typeid is never used, and the type-punned reference is used in both cases. For backwards compatibility with existing code that passes typeid(_Sp_make_shared_tag) that still needs to be handled, but only after checking that the argument is not the type-punned reference (so it's safe to treat as a real std::type_info object). The reference is bound to an object of literal type, so that it doesn't need a guard variable to make its initialization thread-safe. This patch also fixes 87520 by ensuring that the type-punned reference is bound to "a region of storage of suitable size and alignment to contain an object of the reference's type" (as per the proposed resolution of Core DR 453). If all objects are built with the fixed version of GCC then -frtti and -fno-rtti can be mixed freely and std::make_shared will work correctly. If some objects are built with unfixed GCC versions then problems can still arise, depending on which template instantiations are kept by the linker. PR libstdc++/85930 PR libstdc++/87520 * include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_ti) [__cpp_rtti]: Define even when RTTI is enabled. Use array of sizeof(type_info) so that type-punned reference binds to an object of the correct size as well as correct alignment. (_Sp_counted_ptr_inplace::_M_get_deleter) [__cpp_rtti]: Check for _S_ti() reference even when RTTI is enabled. (__shared_ptr(_Sp_make_shared_tag, const _Alloc&, _Args&&...)) [__cpp_rtti]: Pass _S_ti() instead of typeid(_Sp_make_shared_tag). From-SVN: r266376
-rw-r--r--libstdc++-v3/ChangeLog13
-rw-r--r--libstdc++-v3/include/bits/shared_ptr_base.h24
2 files changed, 24 insertions, 13 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index a77596e..267ec39 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,16 @@
+2018-11-22 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/85930
+ PR libstdc++/87520
+ * include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_ti)
+ [__cpp_rtti]: Define even when RTTI is enabled. Use array of
+ sizeof(type_info) so that type-punned reference binds to an object
+ of the correct size as well as correct alignment.
+ (_Sp_counted_ptr_inplace::_M_get_deleter) [__cpp_rtti]: Check for
+ _S_ti() reference even when RTTI is enabled.
+ (__shared_ptr(_Sp_make_shared_tag, const _Alloc&, _Args&&...))
+ [__cpp_rtti]: Pass _S_ti() instead of typeid(_Sp_make_shared_tag).
+
2018-11-21 Jakub Jelinek <jakub@redhat.com>
PR c++/87386
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index 870aeb9..46ff4a7 100644
--- 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;
@@ -510,10 +509,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static const type_info&
_S_ti() noexcept _GLIBCXX_VISIBILITY(default)
{
- alignas(type_info) static constexpr _Sp_make_shared_tag __tag;
+ alignas(type_info) static constexpr char __tag[sizeof(type_info)] = { };
return reinterpret_cast<const type_info&>(__tag);
}
-#endif
};
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
@@ -562,16 +560,20 @@ _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 old libstdc++ headers and RTTI enabled
+ // might 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 +1325,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);
}