Make any_cast compare typeinfo as well as function pointers
authorJonathan Wakely <jwakely@redhat.com>
Thu, 23 May 2019 14:13:18 +0000 (15:13 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 23 May 2019 14:13:18 +0000 (15:13 +0100)
It's possible for the function pointer comparison to fail even though
the type is correct, because the function could be defined multiple
times with different addresses when shared libraries are in use.

Retain the function pointer check for the common case where the check
succeeds, but compare typeinfo (if RTTI is enabled) if the first check
fails.

* include/experimental/any (__any_caster): Use RTTI if comparing
addresses fails, to support non-unique addresses in shared libraries.
* include/std/any (__any_caster): Likewise.

From-SVN: r271557

libstdc++-v3/ChangeLog
libstdc++-v3/include/experimental/any
libstdc++-v3/include/std/any

index 460b734962e1cadd4f6e46dc10dd025bd9ed5716..2d557fc3a78014c0b2fa4a2c2e64f7d48b748c56 100644 (file)
@@ -1,5 +1,9 @@
 2019-05-23  Jonathan Wakely  <jwakely@redhat.com>
 
+       * include/experimental/any (__any_caster): Use RTTI if comparing
+       addresses fails, to support non-unique addresses in shared libraries.
+       * include/std/any (__any_caster): Likewise.
+
        PR libstdc++/90220
        * include/experimental/any (__any_caster): Constrain to only be
        callable for object types. Use remove_cv_t instead of decay_t.
index f1d4bbf788c083afd1e287488e9067646d52b032..f7a4c8fa3945c9ed33a2efe746440651aba00da6 100644 (file)
@@ -432,11 +432,18 @@ inline namespace fundamentals_v1
       // is explicitly specialized and has a no-op _S_manage function.
       using _Vp = conditional_t<__and_<__does_not_decay, __is_copyable>::value,
                                _Up, any::_Op>;
-      if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage)
-       return nullptr;
-      any::_Arg __arg;
-      __any->_M_manager(any::_Op_access, __any, &__arg);
-      return __arg._M_obj;
+      // First try comparing function addresses, which works without RTTI
+      if (__any->_M_manager == &any::_Manager<_Vp>::_S_manage
+#if __cpp_rtti
+         || __any->type() == typeid(_Tp)
+#endif
+         )
+       {
+         any::_Arg __arg;
+         __any->_M_manager(any::_Op_access, __any, &__arg);
+         return __arg._M_obj;
+       }
+      return nullptr;
     }
 
   // This overload exists so that std::any_cast<void(*)()>(a) is well-formed.
index 8cbabdddd9b735479b65b7fac9516f915617ac2d..229c7c6b65ec5cbf38415da886bbb74e7f7c5c2c 100644 (file)
@@ -503,6 +503,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
   // @}
 
+  /// @cond undocumented
   template<typename _Tp>
     void* __any_caster(const any* __any)
     {
@@ -516,8 +517,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Only copy constructible types can be used for contained values:
       else if constexpr (!is_copy_constructible_v<_Up>)
        return nullptr;
-      // This check is equivalent to __any->type() == typeid(_Tp)
-      else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage)
+      // First try comparing function addresses, which works without RTTI
+      else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
+#if __cpp_rtti
+         || __any->type() == typeid(_Tp)
+#endif
+         )
        {
          any::_Arg __arg;
          __any->_M_manager(any::_Op_access, __any, &__arg);
@@ -525,6 +530,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
       return nullptr;
     }
+  /// @endcond
 
   /**
    * @brief Access the contained object.