1 // Copyright 2017 The PDFium Authors
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 <cstddef>
9 #include <functional>
10 #include <type_traits>
11 #include <utility>
12
13 #include "third_party/base/compiler_specific.h"
14
15 // UnownedPtr is a smart pointer class that behaves very much like a
16 // standard C-style pointer. The advantages of using it over raw
17 // pointers are:
18 //
19 // 1. It documents the nature of the pointer with no need to add a comment
20 // explaining that is it // Not owned. Additionally, an attempt to delete
21 // an unowned ptr will fail to compile rather than silently succeeding,
22 // since it is a class and not a raw pointer.
23 //
24 // 2. When built using the memory tool ASAN, the class provides a destructor
25 // which checks that the object being pointed to is still alive.
26 //
27 // Hence, when using UnownedPtr, no dangling pointers are ever permitted,
28 // even if they are not de-referenced after becoming dangling. The style of
29 // programming required is that the lifetime an object containing an
30 // UnownedPtr must be strictly less than the object to which it points.
31 //
32 // The same checks are also performed at assignment time to prove that the
33 // old value was not a dangling pointer, either.
34 //
35 // The array indexing operation [] is not supported on an unowned ptr,
36 // because an unowned ptr expresses a one to one relationship with some
37 // other heap object. Use pdfium::span<> for the cases where indexing
38 // into an unowned array is desired, which performs the same checks.
39
40 namespace pdfium {
41
42 template <typename T>
43 class span;
44
45 } // namespace pdfium
46
47 namespace fxcrt {
48
49 template <class T>
50 class TRIVIAL_ABI GSL_POINTER UnownedPtr {
51 public:
52 constexpr UnownedPtr() noexcept = default;
53
54 // Deliberately implicit to allow returning nullptrs.
55 // NOLINTNEXTLINE(runtime/explicit)
UnownedPtr(std::nullptr_t ptr)56 constexpr UnownedPtr(std::nullptr_t ptr) {}
57
UnownedPtr(T * pObj)58 explicit constexpr UnownedPtr(T* pObj) noexcept : m_pObj(pObj) {}
59
60 // Copy-construct an UnownedPtr.
61 // Required in addition to copy conversion constructor below.
UnownedPtr(const UnownedPtr & that)62 constexpr UnownedPtr(const UnownedPtr& that) noexcept
63 : m_pObj(static_cast<T*>(that)) {}
64
65 // Move-construct an UnownedPtr. After construction, |that| will be NULL.
66 // Required in addition to move conversion constructor below.
UnownedPtr(UnownedPtr && that)67 constexpr UnownedPtr(UnownedPtr&& that) noexcept
68 : m_pObj(that.ExtractAsDangling()) {}
69
70 // Copy-conversion constructor.
71 template <class U,
72 typename = typename std::enable_if<
73 std::is_convertible<U*, T*>::value>::type>
UnownedPtr(const UnownedPtr<U> & that)74 UnownedPtr(const UnownedPtr<U>& that) : UnownedPtr(static_cast<U*>(that)) {}
75
76 // Move-conversion constructor.
77 template <class U,
78 typename = typename std::enable_if<
79 std::is_convertible<U*, T*>::value>::type>
UnownedPtr(UnownedPtr<U> && that)80 UnownedPtr(UnownedPtr<U>&& that) noexcept {
81 Reset(that.ExtractAsDangling());
82 }
83
84 // Assign an UnownedPtr from nullptr.
85 UnownedPtr& operator=(std::nullptr_t) noexcept {
86 Reset();
87 return *this;
88 }
89
90 // Assign an UnownedPtr from a raw ptr.
91 UnownedPtr& operator=(T* that) noexcept {
92 Reset(that);
93 return *this;
94 }
95
96 // Copy-assign an UnownedPtr.
97 // Required in addition to copy conversion assignment below.
98 UnownedPtr& operator=(const UnownedPtr& that) noexcept {
99 if (*this != that)
100 Reset(static_cast<T*>(that));
101 return *this;
102 }
103
104 // Move-assign an UnownedPtr. After assignment, |that| will be NULL.
105 // Required in addition to move conversion assignment below.
106 UnownedPtr& operator=(UnownedPtr&& that) noexcept {
107 if (*this != that)
108 Reset(that.ExtractAsDangling());
109 return *this;
110 }
111
112 // Copy-convert assignment.
113 template <class U,
114 typename = typename std::enable_if<
115 std::is_convertible<U*, T*>::value>::type>
116 UnownedPtr& operator=(const UnownedPtr<U>& that) noexcept {
117 if (*this != that)
118 Reset(that);
119 return *this;
120 }
121
122 // Move-convert assignment. After assignment, |that| will be NULL.
123 template <class U,
124 typename = typename std::enable_if<
125 std::is_convertible<U*, T*>::value>::type>
126 UnownedPtr& operator=(UnownedPtr<U>&& that) noexcept {
127 if (*this != that)
128 Reset(that.ExtractAsDangling());
129 return *this;
130 }
131
~UnownedPtr()132 ~UnownedPtr() {
133 ProbeForLowSeverityLifetimeIssue();
134 m_pObj = nullptr;
135 }
136
137 bool operator==(std::nullptr_t ptr) const { return m_pObj == nullptr; }
138 bool operator==(const UnownedPtr& that) const {
139 return m_pObj == static_cast<T*>(that);
140 }
141 bool operator<(const UnownedPtr& that) const {
142 return std::less<T*>()(m_pObj, static_cast<T*>(that));
143 }
144
145 operator T*() const noexcept { return m_pObj; }
get()146 T* get() const noexcept { return m_pObj; }
147
ExtractAsDangling()148 T* ExtractAsDangling() {
149 ProbeForLowSeverityLifetimeIssue();
150 T* pTemp = nullptr;
151 std::swap(pTemp, m_pObj);
152 return pTemp;
153 }
154
155 explicit operator bool() const { return !!m_pObj; }
156 T& operator*() const { return *m_pObj; }
157 T* operator->() const { return m_pObj; }
158
159 private:
160 friend class pdfium::span<T>;
161
162 void Reset(T* obj = nullptr) {
163 ProbeForLowSeverityLifetimeIssue();
164 m_pObj = obj;
165 }
166
ProbeForLowSeverityLifetimeIssue()167 inline void ProbeForLowSeverityLifetimeIssue() {
168 #if defined(ADDRESS_SANITIZER)
169 if (m_pObj)
170 reinterpret_cast<const volatile uint8_t*>(m_pObj)[0];
171 #endif
172 }
173
ReleaseBadPointer()174 inline void ReleaseBadPointer() {
175 #if defined(ADDRESS_SANITIZER)
176 m_pObj = nullptr;
177 #endif
178 }
179
180 T* m_pObj = nullptr;
181 };
182
183 } // namespace fxcrt
184
185 using fxcrt::UnownedPtr;
186
187 namespace pdfium {
188
189 // Type-deducing wrapper to make an UnownedPtr from an ordinary pointer,
190 // since equivalent constructor is explicit.
191 template <typename T>
WrapUnowned(T * that)192 UnownedPtr<T> WrapUnowned(T* that) {
193 return UnownedPtr<T>(that);
194 }
195
196 } // namespace pdfium
197
198 #endif // CORE_FXCRT_UNOWNED_PTR_H_
199