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