memory: avoid undefined behaviour from downcasting ptr implentation (#5)

* sharedptr: dont downcast ptr implentation

avoid runtime errors of wrong downcasts by adding a underlaying ptr data
getter and only cast the data, downcasting the implentation type isnt
inherited from eachother, while the intention was do upcast/downcast
a derived class to a base class. found with UBSAN "runtime error:
downcast of address which does not point to an object of type
"CSharedPointer_::impl<IKeyboard>" note: object is of type
"Hyprutils::Memory::CSharedPointer_::impl<CKeyboard>"

also make dataNonNull check against != nullptr.

* sharedptr: use reinterpret_cast instead of c style

make it more type safe, C style casts tries every single one until one
works, or not. compilers also produces better warnings/errors when using
c++ casts in favour of C style ones.
This commit is contained in:
Tom Englund 2024-06-28 18:49:58 +02:00 committed by GitHub
parent 1f6bbec595
commit 7e1b6610a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 13 additions and 8 deletions

View file

@ -20,7 +20,7 @@ namespace Hyprutils {
namespace CSharedPointer_ { namespace CSharedPointer_ {
class impl_base { class impl_base {
public: public:
virtual ~impl_base(){}; virtual ~impl_base() {};
virtual void inc() noexcept = 0; virtual void inc() noexcept = 0;
virtual void dec() noexcept = 0; virtual void dec() noexcept = 0;
@ -31,6 +31,7 @@ namespace Hyprutils {
virtual void destroy() noexcept = 0; virtual void destroy() noexcept = 0;
virtual bool destroying() noexcept = 0; virtual bool destroying() noexcept = 0;
virtual bool dataNonNull() noexcept = 0; virtual bool dataNonNull() noexcept = 0;
virtual void* getData() noexcept = 0;
}; };
template <typename T> template <typename T>
@ -107,6 +108,10 @@ namespace Hyprutils {
} }
virtual bool dataNonNull() noexcept { virtual bool dataNonNull() noexcept {
return _data != nullptr;
}
virtual void* getData() noexcept {
return _data; return _data;
} }
@ -213,11 +218,11 @@ namespace Hyprutils {
} }
bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const { bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const {
return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(lhs.impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
bool operator<(const CSharedPointer& rhs) const { bool operator<(const CSharedPointer& rhs) const {
return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
T* operator->() const { T* operator->() const {
@ -234,7 +239,7 @@ namespace Hyprutils {
} }
T* get() const { T* get() const {
return (T*)(impl_ ? static_cast<CSharedPointer_::impl<T>*>(impl_)->_data : nullptr); return impl_ ? static_cast<T*>(impl_->getData()) : nullptr;
} }
unsigned int strongRef() const { unsigned int strongRef() const {

View file

@ -80,7 +80,7 @@ namespace Hyprutils {
/* create a weak ptr from a shared ptr with assignment */ /* create a weak ptr from a shared ptr with assignment */
template <typename U> template <typename U>
validHierarchy<const CWeakPointer<U>&> operator=(const CSharedPointer<U>& rhs) { validHierarchy<const CWeakPointer<U>&> operator=(const CSharedPointer<U>& rhs) {
if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_) if (reinterpret_cast<uintptr_t>(impl_) == reinterpret_cast<uintptr_t>(rhs.impl_))
return *this; return *this;
decrementWeak(); decrementWeak();
@ -139,15 +139,15 @@ namespace Hyprutils {
} }
bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const { bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const {
return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(lhs.impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
bool operator<(const CWeakPointer& rhs) const { bool operator<(const CWeakPointer& rhs) const {
return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
T* get() const { T* get() const {
return (T*)(impl_ ? static_cast<CSharedPointer_::impl<T>*>(impl_)->_data : nullptr); return impl_ ? static_cast<T*>(impl_->getData()) : nullptr;
} }
T* operator->() const { T* operator->() const {