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