• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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