1 // Copyright 2017 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CORE_FXCRT_UNOWNED_PTR_H_ 6 #define CORE_FXCRT_UNOWNED_PTR_H_ 7 8 #include <functional> 9 #include <memory> 10 #include <type_traits> 11 #include <utility> 12 13 // UnownedPtr is a smart pointer class that behaves very much like a 14 // standard C-style pointer. The advantages of using it over raw 15 // pointers are: 16 // 17 // 1. It documents the nature of the pointer with no need to add a comment 18 // explaining that is it // Not owned. Additionally, an attempt to delete 19 // an unowned ptr will fail to compile rather than silently succeeding, 20 // since it is a class and not a raw pointer. 21 // 22 // 2. When built using the memory tool ASAN, the class provides a destructor 23 // which checks that the object being pointed to is still alive. 24 // 25 // Hence, when using UnownedPtr, no dangling pointers are ever permitted, 26 // even if they are not de-referenced after becoming dangling. The style of 27 // programming required is that the lifetime an object containing an 28 // UnownedPtr must be strictly less than the object to which it points. 29 // 30 // The same checks are also performed at assignment time to prove that the 31 // old value was not a dangling pointer, either. 32 // 33 // The array indexing operation [] is not supported on an unowned ptr, 34 // because an unowned ptr expresses a one to one relationship with some 35 // other heap object. Use pdfium::span<> for the cases where indexing 36 // into an unowned array is desired, which performs the same checks. 37 38 namespace pdfium { 39 40 template <typename T> 41 class span; 42 43 } // namespace pdfium 44 45 namespace fxcrt { 46 47 template <class T> 48 class UnownedPtr { 49 public: 50 constexpr UnownedPtr() noexcept = default; 51 constexpr UnownedPtr(const UnownedPtr& that) noexcept = default; 52 53 // Move-construct an UnownedPtr. After construction, |that| will be NULL. UnownedPtr(UnownedPtr && that)54 constexpr UnownedPtr(UnownedPtr&& that) noexcept : m_pObj(that.Release()) {} 55 56 template <typename U> UnownedPtr(U * pObj)57 explicit constexpr UnownedPtr(U* pObj) noexcept : m_pObj(pObj) {} 58 59 // Deliberately implicit to allow returning nullptrs. 60 // NOLINTNEXTLINE(runtime/explicit) UnownedPtr(std::nullptr_t ptr)61 constexpr UnownedPtr(std::nullptr_t ptr) noexcept {} 62 ~UnownedPtr()63 ~UnownedPtr() { ProbeForLowSeverityLifetimeIssue(); } 64 65 void Reset(T* obj = nullptr) { 66 ProbeForLowSeverityLifetimeIssue(); 67 m_pObj = obj; 68 } 69 70 UnownedPtr& operator=(T* that) noexcept { 71 Reset(that); 72 return *this; 73 } 74 75 UnownedPtr& operator=(const UnownedPtr& that) noexcept { 76 if (*this != that) 77 Reset(that.Get()); 78 return *this; 79 } 80 81 // Move-assign an UnownedPtr. After assignment, |that| will be NULL. 82 UnownedPtr& operator=(UnownedPtr&& that) noexcept { 83 if (*this != that) 84 Reset(that.Release()); 85 return *this; 86 } 87 88 bool operator==(const UnownedPtr& that) const { return Get() == that.Get(); } 89 bool operator!=(const UnownedPtr& that) const { return !(*this == that); } 90 bool operator<(const UnownedPtr& that) const { 91 return std::less<T*>()(Get(), that.Get()); 92 } 93 94 template <typename U> 95 bool operator==(const U* that) const { 96 return Get() == that; 97 } 98 99 template <typename U> 100 bool operator!=(const U* that) const { 101 return !(*this == that); 102 } 103 Get()104 T* Get() const noexcept { return m_pObj; } 105 Release()106 T* Release() { 107 ProbeForLowSeverityLifetimeIssue(); 108 T* pTemp = nullptr; 109 std::swap(pTemp, m_pObj); 110 return pTemp; 111 } 112 113 explicit operator bool() const { return !!m_pObj; } 114 T& operator*() const { return *m_pObj; } 115 T* operator->() const { return m_pObj; } 116 117 private: 118 friend class pdfium::span<T>; 119 ProbeForLowSeverityLifetimeIssue()120 inline void ProbeForLowSeverityLifetimeIssue() { 121 #if defined(ADDRESS_SANITIZER) 122 if (m_pObj) 123 reinterpret_cast<const volatile uint8_t*>(m_pObj)[0]; 124 #endif 125 } 126 ReleaseBadPointer()127 inline void ReleaseBadPointer() { 128 #if defined(ADDRESS_SANITIZER) 129 m_pObj = nullptr; 130 #endif 131 } 132 133 T* m_pObj = nullptr; 134 }; 135 136 template <typename T, typename U> 137 inline bool operator==(const U* lhs, const UnownedPtr<T>& rhs) { 138 return rhs == lhs; 139 } 140 141 template <typename T, typename U> 142 inline bool operator!=(const U* lhs, const UnownedPtr<T>& rhs) { 143 return rhs != lhs; 144 } 145 146 } // namespace fxcrt 147 148 using fxcrt::UnownedPtr; 149 150 #endif // CORE_FXCRT_UNOWNED_PTR_H_ 151