Fix undefined behaviour in base::weak_ptr.

Regression was introduced in 1c79f85d00.

Invalid casts lead to crashes in macOS notifications handling.
Casts were T* -> has_weak_ptr* -> void* -> T* which was not working
in case T had has_weak_ptr as not first base class.

Now it uses just T* -> has_weak_ptr* -> T* casts.
This commit is contained in:
John Preston 2018-10-10 00:17:25 +03:00
parent 9436789d6d
commit b6128b6fe0
1 changed files with 9 additions and 13 deletions

View File

@ -11,14 +11,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <memory> #include <memory>
namespace base { namespace base {
class has_weak_ptr;
namespace details { namespace details {
struct alive_tracker { struct alive_tracker {
explicit alive_tracker(const void *value) : value(value) { explicit alive_tracker(const has_weak_ptr *value) : value(value) {
} }
std::atomic<int> counter = 1; std::atomic<int> counter = 1;
std::atomic<const void*> value; std::atomic<const has_weak_ptr*> value;
}; };
inline alive_tracker *check_and_increment(alive_tracker *tracker) noexcept { inline alive_tracker *check_and_increment(alive_tracker *tracker) noexcept {
@ -36,8 +39,6 @@ inline void decrement(alive_tracker *tracker) noexcept {
} // namespace details } // namespace details
class has_weak_ptr;
template <typename T> template <typename T>
class weak_ptr; class weak_ptr;
@ -69,8 +70,7 @@ private:
details::alive_tracker *incrementAliveTracker() const { details::alive_tracker *incrementAliveTracker() const {
auto current = _alive.load(); auto current = _alive.load();
if (!current) { if (!current) {
auto alive = std::make_unique<details::alive_tracker>( auto alive = std::make_unique<details::alive_tracker>(this);
static_cast<const void*>(this));
if (_alive.compare_exchange_strong(current, alive.get())) { if (_alive.compare_exchange_strong(current, alive.get())) {
return alive.release(); return alive.release();
} }
@ -178,15 +178,11 @@ public:
} }
T *get() const noexcept { T *get() const noexcept {
const auto strong = _alive ? _alive->value.load() : nullptr;
if constexpr (std::is_const_v<T>) { if constexpr (std::is_const_v<T>) {
return _alive return static_cast<T*>(strong);
? static_cast<T*>(_alive->value.load())
: nullptr;
} else { } else {
return _alive return const_cast<T*>(static_cast<const T*>(strong));
? const_cast<T*>(
static_cast<const T*>(_alive->value.load()))
: nullptr;
} }
} }
explicit operator bool() const noexcept { explicit operator bool() const noexcept {