123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- #ifndef BASE_MEMORY_CHECKED_PTR_H_
- #define BASE_MEMORY_CHECKED_PTR_H_
- #include <stddef.h>
- #include <stdint.h>
- #include <utility>
- #include "base/compiler_specific.h"
- #include "base/logging.h"
- #include "build/build_config.h"
- #define CHECKED_PTR2_PROTECTION_ENABLED 0
- #define CHECKED_PTR2_USE_NO_OP_WRAPPER 0
- #define CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED 0
- #define CHECKED_PTR2_AVOID_BRANCH_WHEN_DEREFERENCING 0
- namespace base {
- namespace internal {
- struct CheckedPtrNoOpImpl {
-
-
-
- static ALWAYS_INLINE uintptr_t WrapRawPtr(const volatile void* cv_ptr) {
- return reinterpret_cast<uintptr_t>(cv_ptr);
- }
-
-
- static constexpr ALWAYS_INLINE uintptr_t GetWrappedNullPtr() {
-
-
- return 0;
- }
-
-
- static ALWAYS_INLINE void* SafelyUnwrapPtrForDereference(
- uintptr_t wrapped_ptr) {
- return reinterpret_cast<void*>(wrapped_ptr);
- }
-
-
- static ALWAYS_INLINE void* SafelyUnwrapPtrForExtraction(
- uintptr_t wrapped_ptr) {
- return reinterpret_cast<void*>(wrapped_ptr);
- }
-
-
- static ALWAYS_INLINE void* UnsafelyUnwrapPtrForComparison(
- uintptr_t wrapped_ptr) {
- return reinterpret_cast<void*>(wrapped_ptr);
- }
-
- static ALWAYS_INLINE uintptr_t Advance(uintptr_t wrapped_ptr, size_t delta) {
- return wrapped_ptr + delta;
- }
-
- static ALWAYS_INLINE void IncrementSwapCountForTest() {}
- };
- #if defined(ARCH_CPU_64_BITS)
- constexpr int kValidAddressBits = 48;
- constexpr uintptr_t kAddressMask = (1ull << kValidAddressBits) - 1;
- constexpr int kGenerationBits = sizeof(uintptr_t) * 8 - kValidAddressBits;
- constexpr uintptr_t kGenerationMask = ~kAddressMask;
- constexpr int kTopBitShift = 63;
- constexpr uintptr_t kTopBit = 1ull << kTopBitShift;
- static_assert(kTopBit << 1 == 0, "kTopBit should really be the top bit");
- static_assert((kTopBit & kGenerationMask) > 0,
- "kTopBit bit must be inside the generation region");
- static volatile bool g_enabled = true;
- struct CheckedPtr2Impl {
- static_assert(sizeof(uintptr_t) == 8,
- "only 64-bit architectures are supported");
-
- static ALWAYS_INLINE uintptr_t WrapRawPtr(const volatile void* cv_ptr) {
- void* ptr = const_cast<void*>(cv_ptr);
- uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
- #if CHECKED_PTR2_USE_NO_OP_WRAPPER
- static_assert(!CHECKED_PTR2_PROTECTION_ENABLED, "");
- #else
-
-
- DCHECK_EQ(ExtractGeneration(addr), 0ull);
-
-
- if (ptr == nullptr || !g_enabled) {
- return addr;
- }
-
-
-
-
-
- volatile size_t size = (addr & (addr - 1)) ^ addr;
- if (addr % size != 0) {
- DCHECK(false);
- return addr;
- }
-
-
-
-
-
- static_assert(sizeof(uint16_t) * 8 == kGenerationBits, "");
- #if CHECKED_PTR2_PROTECTION_ENABLED
- uintptr_t generation = *(static_cast<volatile uint16_t*>(ptr) - 1);
- #else
-
-
-
-
-
-
- uintptr_t generation = *(static_cast<volatile uint16_t*>(ptr));
- #endif
- generation <<= kValidAddressBits;
- addr |= generation;
- #if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
-
- addr |= kTopBit;
- #if !CHECKED_PTR2_PROTECTION_ENABLED
-
-
-
- addr &= kAddressMask;
- #endif
- #endif
- #endif
- return addr;
- }
-
-
- static constexpr ALWAYS_INLINE uintptr_t GetWrappedNullPtr() {
- return kWrappedNullPtr;
- }
- static ALWAYS_INLINE uintptr_t
- SafelyUnwrapPtrInternal(uintptr_t wrapped_ptr) {
- #if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
-
-
-
-
-
-
-
-
-
-
-
-
-
- uintptr_t enabled = wrapped_ptr & kTopBit;
-
- DCHECK(!(enabled == 0 && (ExtractGeneration(wrapped_ptr)) != 0));
- uintptr_t offset = enabled >> kTopBitShift;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- volatile uint16_t* generation_ptr =
- reinterpret_cast<volatile uint16_t*>(ExtractAddress(wrapped_ptr)) -
- offset;
- uintptr_t generation = *generation_ptr;
-
-
-
-
-
-
-
- generation <<= kValidAddressBits;
- generation |= enabled;
-
-
-
-
-
-
-
-
- uintptr_t mask = static_cast<intptr_t>(enabled) >> (kGenerationBits - 1);
- generation &= mask;
-
-
-
-
-
-
-
-
-
-
- static_assert(CHECKED_PTR2_AVOID_BRANCH_WHEN_DEREFERENCING, "");
- return generation ^ wrapped_ptr;
- #else
- uintptr_t ptr_generation = wrapped_ptr >> kValidAddressBits;
- if (ptr_generation > 0) {
-
-
-
-
-
- #if CHECKED_PTR2_PROTECTION_ENABLED
- uintptr_t read_generation =
- *(reinterpret_cast<volatile uint16_t*>(ExtractAddress(wrapped_ptr)) -
- 1);
- #else
-
- uintptr_t read_generation =
- *(reinterpret_cast<volatile uint16_t*>(ExtractAddress(wrapped_ptr)));
- #endif
- #if CHECKED_PTR2_AVOID_BRANCH_WHEN_DEREFERENCING
-
-
-
- read_generation <<= kValidAddressBits;
- return read_generation ^ wrapped_ptr;
- #else
- #if CHECKED_PTR2_PROTECTION_ENABLED
- if (UNLIKELY(ptr_generation != read_generation))
- IMMEDIATE_CRASH();
- #else
-
-
- volatile bool x = false;
- if (ptr_generation != read_generation)
- x = true;
- #endif
- return wrapped_ptr & kAddressMask;
- #endif
- }
- return wrapped_ptr;
- #endif
- }
-
-
- static ALWAYS_INLINE void* SafelyUnwrapPtrForDereference(
- uintptr_t wrapped_ptr) {
- #if CHECKED_PTR2_PROTECTION_ENABLED
- return reinterpret_cast<void*>(SafelyUnwrapPtrInternal(wrapped_ptr));
- #else
-
-
-
- volatile uintptr_t addr = SafelyUnwrapPtrInternal(wrapped_ptr);
- return reinterpret_cast<void*>(addr);
- #endif
- }
-
-
- static ALWAYS_INLINE void* SafelyUnwrapPtrForExtraction(
- uintptr_t wrapped_ptr) {
- #if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
-
-
-
- if (wrapped_ptr == kWrappedNullPtr)
- return nullptr;
- return reinterpret_cast<void*>(SafelyUnwrapPtrForDereference(wrapped_ptr));
- #else
-
-
- return reinterpret_cast<void*>(SafelyUnwrapPtrForDereference(wrapped_ptr));
- #endif
- }
-
-
- static ALWAYS_INLINE void* UnsafelyUnwrapPtrForComparison(
- uintptr_t wrapped_ptr) {
- return reinterpret_cast<void*>(ExtractAddress(wrapped_ptr));
- }
-
- static ALWAYS_INLINE uintptr_t Advance(uintptr_t wrapped_ptr, size_t delta) {
-
-
- return ExtractAddress(wrapped_ptr) + delta;
- }
-
- static ALWAYS_INLINE void IncrementSwapCountForTest() {}
- private:
- static ALWAYS_INLINE uintptr_t ExtractAddress(uintptr_t wrapped_ptr) {
- return wrapped_ptr & kAddressMask;
- }
- static ALWAYS_INLINE uintptr_t ExtractGeneration(uintptr_t wrapped_ptr) {
- return wrapped_ptr & kGenerationMask;
- }
-
-
- static constexpr uintptr_t kWrappedNullPtr = 0;
- };
- #endif
- template <typename T>
- struct DereferencedPointerType {
- using Type = decltype(*std::declval<T*>());
- };
- template <>
- struct DereferencedPointerType<void> {};
- }
- template <typename T,
- #if defined(ARCH_CPU_64_BITS)
- typename Impl = internal::CheckedPtr2Impl>
- #else
- typename Impl = internal::CheckedPtrNoOpImpl>
- #endif
- class CheckedPtr {
- public:
-
-
-
-
-
- constexpr CheckedPtr() noexcept = default;
-
-
- constexpr ALWAYS_INLINE CheckedPtr(nullptr_t) noexcept
- : wrapped_ptr_(Impl::GetWrappedNullPtr()) {}
-
-
- ALWAYS_INLINE CheckedPtr(T* p) noexcept : wrapped_ptr_(Impl::WrapRawPtr(p)) {}
-
-
-
-
-
- CheckedPtr(const CheckedPtr&) noexcept = default;
- CheckedPtr(CheckedPtr&&) noexcept = default;
- CheckedPtr& operator=(const CheckedPtr&) noexcept = default;
- CheckedPtr& operator=(CheckedPtr&&) noexcept = default;
- ALWAYS_INLINE CheckedPtr& operator=(T* p) noexcept {
- wrapped_ptr_ = Impl::WrapRawPtr(p);
- return *this;
- }
- ALWAYS_INLINE CheckedPtr& operator=(std::nullptr_t) noexcept {
- wrapped_ptr_ = Impl::GetWrappedNullPtr();
- return *this;
- }
- ~CheckedPtr() = default;
-
-
- ALWAYS_INLINE T* get() const { return GetForExtraction(); }
- explicit ALWAYS_INLINE operator bool() const {
- return wrapped_ptr_ != Impl::GetWrappedNullPtr();
- }
-
-
- template <typename U = T,
- typename V = typename internal::DereferencedPointerType<U>::Type>
- ALWAYS_INLINE V& operator*() const {
- return *GetForDereference();
- }
- ALWAYS_INLINE T* operator->() const { return GetForDereference(); }
-
-
- ALWAYS_INLINE operator T*() const { return GetForExtraction(); }
- template <typename U>
- explicit ALWAYS_INLINE operator U*() const {
- return static_cast<U*>(GetForExtraction());
- }
- ALWAYS_INLINE CheckedPtr& operator++() {
- wrapped_ptr_ = Impl::Advance(wrapped_ptr_, sizeof(T));
- return *this;
- }
- ALWAYS_INLINE CheckedPtr& operator--() {
- wrapped_ptr_ = Impl::Advance(wrapped_ptr_, -sizeof(T));
- return *this;
- }
- ALWAYS_INLINE CheckedPtr operator++(int ) {
- CheckedPtr result = *this;
- ++(*this);
- return result;
- }
- ALWAYS_INLINE CheckedPtr operator--(int ) {
- CheckedPtr result = *this;
- --(*this);
- return result;
- }
- ALWAYS_INLINE CheckedPtr& operator+=(ptrdiff_t delta_elems) {
- wrapped_ptr_ = Impl::Advance(wrapped_ptr_, delta_elems * sizeof(T));
- return *this;
- }
- ALWAYS_INLINE CheckedPtr& operator-=(ptrdiff_t delta_elems) {
- return *this += -delta_elems;
- }
-
-
-
- friend ALWAYS_INLINE bool operator==(const CheckedPtr& lhs,
- const CheckedPtr& rhs) {
- return lhs.GetForComparison() == rhs.GetForComparison();
- }
- friend ALWAYS_INLINE bool operator!=(const CheckedPtr& lhs,
- const CheckedPtr& rhs) {
- return !(lhs == rhs);
- }
- friend ALWAYS_INLINE bool operator==(const CheckedPtr& lhs, T* rhs) {
- return lhs.GetForComparison() == rhs;
- }
- friend ALWAYS_INLINE bool operator!=(const CheckedPtr& lhs, T* rhs) {
- return !(lhs == rhs);
- }
- friend ALWAYS_INLINE bool operator==(T* lhs, const CheckedPtr& rhs) {
- return rhs == lhs;
- }
- friend ALWAYS_INLINE bool operator!=(T* lhs, const CheckedPtr& rhs) {
- return rhs != lhs;
- }
-
-
- template <typename U>
- friend ALWAYS_INLINE bool operator==(const CheckedPtr& lhs,
- const CheckedPtr<U, Impl>& rhs) {
-
-
- return lhs.GetForComparison() ==
- static_cast<std::add_cv_t<T>*>(rhs.GetForComparison());
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator!=(const CheckedPtr& lhs,
- const CheckedPtr<U, Impl>& rhs) {
- return !(lhs == rhs);
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator==(const CheckedPtr& lhs, U* rhs) {
-
-
- return lhs.GetForComparison() == static_cast<std::add_cv_t<T>*>(rhs);
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator!=(const CheckedPtr& lhs, U* rhs) {
- return !(lhs == rhs);
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator==(U* lhs, const CheckedPtr& rhs) {
- return rhs == lhs;
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator!=(U* lhs, const CheckedPtr& rhs) {
- return rhs != lhs;
- }
-
-
-
- friend ALWAYS_INLINE bool operator==(const CheckedPtr& lhs, nullptr_t) {
- return !lhs;
- }
- friend ALWAYS_INLINE bool operator!=(const CheckedPtr& lhs, nullptr_t) {
- return !!lhs;
- }
- friend ALWAYS_INLINE bool operator==(nullptr_t, const CheckedPtr& rhs) {
- return !rhs;
- }
- friend ALWAYS_INLINE bool operator!=(nullptr_t, const CheckedPtr& rhs) {
- return !!rhs;
- }
- friend ALWAYS_INLINE void swap(CheckedPtr& lhs, CheckedPtr& rhs) noexcept {
- Impl::IncrementSwapCountForTest();
- std::swap(lhs.wrapped_ptr_, rhs.wrapped_ptr_);
- }
- private:
-
-
-
- ALWAYS_INLINE T* GetForDereference() const {
- return static_cast<T*>(Impl::SafelyUnwrapPtrForDereference(wrapped_ptr_));
- }
-
-
-
- ALWAYS_INLINE T* GetForExtraction() const {
- return static_cast<T*>(Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_));
- }
-
-
-
- ALWAYS_INLINE T* GetForComparison() const {
- return static_cast<T*>(Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_));
- }
-
-
- uintptr_t wrapped_ptr_;
- template <typename U, typename V>
- friend class CheckedPtr;
- };
- }
- using base::CheckedPtr;
- #endif
|