Skip to content

Commit

Permalink
Make any_cast compare typeinfo as well as function pointers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jwakely committed May 23, 2019
1 parent 7dbab5d commit aa573a6
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
4 changes: 4 additions & 0 deletions libstdc++-v3/ChangeLog
@@ -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.
Expand Down
17 changes: 12 additions & 5 deletions libstdc++-v3/include/experimental/any
Expand Up @@ -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.
Expand Down
10 changes: 8 additions & 2 deletions libstdc++-v3/include/std/any
Expand Up @@ -503,6 +503,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
// @}

/// @cond undocumented
template<typename _Tp>
void* __any_caster(const any* __any)
{
Expand All @@ -516,15 +517,20 @@ _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);
return __arg._M_obj;
}
return nullptr;
}
/// @endcond

/**
* @brief Access the contained object.
Expand Down

0 comments on commit aa573a6

Please sign in to comment.