Commit 8900d7c4 by Abseil Team Committed by Copybara-Service

Mutex: Fix Condition pointer-to-member cast to respect const qualifier

Previously, `absl::Condition` incorrectly used the same (non-`const`)
pointer-to-method type when wrapping both `const` and non-`const` methods.

Unfortunately, this is undefined behavior according to `[expr.reinterpret.cast]`
in the C++ standard:

> The effect of calling a function through a pointer to a function type that is
> not the same as the type used in the definition of the function is undefined.

This fixes the UB.

PiperOrigin-RevId: 591981682
Change-Id: Iaca955346699417232383d3a1800ea9b82ea5761
parent d22aa4df
...@@ -848,7 +848,7 @@ class Condition { ...@@ -848,7 +848,7 @@ class Condition {
static bool CallVoidPtrFunction(const Condition*); static bool CallVoidPtrFunction(const Condition*);
template <typename T> template <typename T>
static bool CastAndCallFunction(const Condition* c); static bool CastAndCallFunction(const Condition* c);
template <typename T> template <typename T, typename ConditionMethodPtr>
static bool CastAndCallMethod(const Condition* c); static bool CastAndCallMethod(const Condition* c);
// Helper methods for storing, validating, and reading callback arguments. // Helper methods for storing, validating, and reading callback arguments.
...@@ -1080,12 +1080,12 @@ inline void Mutex::Dtor() {} ...@@ -1080,12 +1080,12 @@ inline void Mutex::Dtor() {}
inline CondVar::CondVar() : cv_(0) {} inline CondVar::CondVar() : cv_(0) {}
// static // static
template <typename T> template <typename T, typename ConditionMethodPtr>
bool Condition::CastAndCallMethod(const Condition* c) { bool Condition::CastAndCallMethod(const Condition* c) {
T* object = static_cast<T*>(c->arg_); T* object = static_cast<T*>(c->arg_);
bool (T::*method_pointer)(); ConditionMethodPtr condition_method_pointer;
c->ReadCallback(&method_pointer); c->ReadCallback(&condition_method_pointer);
return (object->*method_pointer)(); return (object->*condition_method_pointer)();
} }
// static // static
...@@ -1115,7 +1115,7 @@ inline Condition::Condition(bool (*func)(T*), ...@@ -1115,7 +1115,7 @@ inline Condition::Condition(bool (*func)(T*),
template <typename T> template <typename T>
inline Condition::Condition(T* object, inline Condition::Condition(T* object,
bool (absl::internal::identity<T>::type::*method)()) bool (absl::internal::identity<T>::type::*method)())
: eval_(&CastAndCallMethod<T>), arg_(object) { : eval_(&CastAndCallMethod<T, decltype(method)>), arg_(object) {
static_assert(sizeof(&method) <= sizeof(callback_), static_assert(sizeof(&method) <= sizeof(callback_),
"An overlarge method pointer was passed to Condition."); "An overlarge method pointer was passed to Condition.");
StoreCallback(method); StoreCallback(method);
...@@ -1125,7 +1125,7 @@ template <typename T> ...@@ -1125,7 +1125,7 @@ template <typename T>
inline Condition::Condition(const T* object, inline Condition::Condition(const T* object,
bool (absl::internal::identity<T>::type::*method)() bool (absl::internal::identity<T>::type::*method)()
const) const)
: eval_(&CastAndCallMethod<T>), : eval_(&CastAndCallMethod<const T, decltype(method)>),
arg_(reinterpret_cast<void*>(const_cast<T*>(object))) { arg_(reinterpret_cast<void*>(const_cast<T*>(object))) {
StoreCallback(method); StoreCallback(method);
} }
......
...@@ -977,6 +977,15 @@ TEST(Mutex, FunctionPointerConditionWithDerivedToBaseConversion) { ...@@ -977,6 +977,15 @@ TEST(Mutex, FunctionPointerConditionWithDerivedToBaseConversion) {
const Derived *>::value)); const Derived *>::value));
} }
struct Constable {
bool WotsAllThisThen() const { return true; }
};
TEST(Mutex, FunctionPointerConditionWithConstMethod) {
const Constable chapman;
EXPECT_TRUE(absl::Condition(&chapman, &Constable::WotsAllThisThen).Eval());
}
struct True { struct True {
template <class... Args> template <class... Args>
bool operator()(Args...) const { bool operator()(Args...) const {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment