mirror of https://github.com/procxx/kepka.git
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:
parent
9436789d6d
commit
b6128b6fe0
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue