summaryrefslogtreecommitdiff
path: root/chromium/third_party/pdfium/core/fxcrt/unowned_ptr.h
blob: 85d635d21ec18d02f18b296df2d99d9fc10881b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2017 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CORE_FXCRT_UNOWNED_PTR_H_
#define CORE_FXCRT_UNOWNED_PTR_H_

#include <functional>
#include <type_traits>
#include <utility>
#include <stdint.h>

// UnownedPtr is a smart pointer class that behaves very much like a
// standard C-style pointer. The advantages of using it over raw
// pointers are:
//
// 1. It documents the nature of the pointer with no need to add a comment
//    explaining that is it // Not owned. Additionally, an attempt to delete
//    an unowned ptr will fail to compile rather than silently succeeding,
//    since it is a class and not a raw pointer.
//
// 2. When built using the memory tool ASAN, the class provides a destructor
//    which checks that the object being pointed to is still alive.
//
// Hence, when using UnownedPtr, no dangling pointers are ever permitted,
// even if they are not de-referenced after becoming dangling. The style of
// programming required is that the lifetime an object containing an
// UnownedPtr must be strictly less than the object to which it points.
//
// The same checks are also performed at assignment time to prove that the
// old value was not a dangling pointer, either.
//
// The array indexing operation [] is not supported on an unowned ptr,
// because an unowned ptr expresses a one to one relationship with some
// other heap object. Use pdfium::span<> for the cases where indexing
// into an unowned array is desired, which performs the same checks.

namespace pdfium {

template <typename T>
class span;

}  // namespace pdfium

namespace fxcrt {

template <class T>
class UnownedPtr {
 public:
  constexpr UnownedPtr() noexcept = default;
  constexpr UnownedPtr(const UnownedPtr& that) noexcept = default;

  // Move-construct an UnownedPtr. After construction, |that| will be NULL.
  constexpr UnownedPtr(UnownedPtr&& that) noexcept : m_pObj(that.Release()) {}

  template <typename U>
  explicit constexpr UnownedPtr(U* pObj) noexcept : m_pObj(pObj) {}

  // Deliberately implicit to allow returning nullptrs.
  // NOLINTNEXTLINE(runtime/explicit)
  constexpr UnownedPtr(std::nullptr_t ptr) noexcept {}

  ~UnownedPtr() {
    ProbeForLowSeverityLifetimeIssue();
    m_pObj = nullptr;
  }

  void Reset(T* obj = nullptr) {
    ProbeForLowSeverityLifetimeIssue();
    m_pObj = obj;
  }

  UnownedPtr& operator=(T* that) noexcept {
    Reset(that);
    return *this;
  }

  UnownedPtr& operator=(const UnownedPtr& that) noexcept {
    if (*this != that)
      Reset(that.Get());
    return *this;
  }

  // Move-assign an UnownedPtr. After assignment, |that| will be NULL.
  UnownedPtr& operator=(UnownedPtr&& that) noexcept {
    if (*this != that)
      Reset(that.Release());
    return *this;
  }

  bool operator==(const UnownedPtr& that) const { return Get() == that.Get(); }
  bool operator!=(const UnownedPtr& that) const { return !(*this == that); }
  bool operator<(const UnownedPtr& that) const {
    return std::less<T*>()(Get(), that.Get());
  }

  operator T*() const noexcept { return Get(); }
  T* Get() const noexcept { return m_pObj; }

  T* Release() {
    ProbeForLowSeverityLifetimeIssue();
    T* pTemp = nullptr;
    std::swap(pTemp, m_pObj);
    return pTemp;
  }

  explicit operator bool() const { return !!m_pObj; }
  T& operator*() const { return *m_pObj; }
  T* operator->() const { return m_pObj; }

 private:
  friend class pdfium::span<T>;

  inline void ProbeForLowSeverityLifetimeIssue() {
#if defined(ADDRESS_SANITIZER)
    if (m_pObj)
      reinterpret_cast<const volatile uint8_t*>(m_pObj)[0];
#endif
  }

  inline void ReleaseBadPointer() {
#if defined(ADDRESS_SANITIZER)
    m_pObj = nullptr;
#endif
  }

  T* m_pObj = nullptr;
};

}  // namespace fxcrt

using fxcrt::UnownedPtr;

#endif  // CORE_FXCRT_UNOWNED_PTR_H_