raw_ref.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright 2022 The Chromium 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. #ifndef BASE_MEMORY_RAW_REF_H_
  5. #define BASE_MEMORY_RAW_REF_H_
  6. #include <memory>
  7. #include <type_traits>
  8. #include <utility>
  9. #include "base/compiler_specific.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "third_party/abseil-cpp/absl/base/attributes.h"
  12. namespace base {
  13. template <class T, class Impl>
  14. class raw_ref;
  15. namespace internal {
  16. template <class T>
  17. struct is_raw_ref : std::false_type {};
  18. template <class T, class I>
  19. struct is_raw_ref<::base::raw_ref<T, I>> : std::true_type {};
  20. template <class T>
  21. constexpr inline bool is_raw_ref_v = is_raw_ref<T>::value;
  22. } // namespace internal
  23. // A smart pointer for a pointer which can not be null, and which provides
  24. // Use-after-Free protection in the same ways as raw_ptr. This class acts like a
  25. // combination of std::reference_wrapper and raw_ptr.
  26. //
  27. // See raw_ptr and //base/memory/raw_ptr.md for more details on the
  28. // Use-after-Free protection.
  29. //
  30. // # Use after move
  31. //
  32. // The raw_ref type will abort if used after being moved.
  33. //
  34. // # Constness
  35. //
  36. // Use a `const raw_ref<T>` when the smart pointer should not be able to rebind
  37. // to a new reference. Use a `const raw_ref<const T>` do the same for a const
  38. // reference, which is like `const T&`.
  39. //
  40. // Unlike a native `T&` reference, a mutable `raw_ref<T>` can be changed
  41. // independent of the underlying `T`, similar to `std::reference_wrapper`. That
  42. // means the reference inside it can be moved and reassigned.
  43. template <class T, class Impl = DefaultRawPtrImpl>
  44. class TRIVIAL_ABI GSL_POINTER raw_ref {
  45. using Inner = raw_ptr<T, Impl>;
  46. // These impls do not clear on move, which produces an inconsistent behaviour.
  47. // We want consistent behaviour such that using a raw_ref after move is caught
  48. // and aborts. Failure to clear would be indicated by the related death tests
  49. // not CHECKing appropriately.
  50. static constexpr bool need_clear_after_move =
  51. std::is_same_v<Impl, internal::RawPtrNoOpImpl> ||
  52. #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
  53. std::is_same_v<Impl,
  54. internal::MTECheckedPtrImpl<
  55. internal::MTECheckedPtrImplPartitionAllocSupport>> ||
  56. #endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
  57. std::is_same_v<Impl, internal::AsanBackupRefPtrImpl>;
  58. public:
  59. ALWAYS_INLINE explicit raw_ref(T& p) noexcept : inner_(std::addressof(p)) {}
  60. ALWAYS_INLINE raw_ref& operator=(T& p) noexcept {
  61. inner_.operator=(&p);
  62. return *this;
  63. }
  64. // Disallow holding references to temporaries.
  65. raw_ref(const T&& p) = delete;
  66. raw_ref& operator=(const T&& p) = delete;
  67. ALWAYS_INLINE raw_ref(const raw_ref& p) noexcept : inner_(p.inner_) {
  68. CHECK(inner_.get()); // Catch use-after-move.
  69. }
  70. ALWAYS_INLINE raw_ref(raw_ref&& p) noexcept : inner_(std::move(p.inner_)) {
  71. CHECK(inner_.get()); // Catch use-after-move.
  72. if constexpr (need_clear_after_move)
  73. p.inner_ = nullptr;
  74. }
  75. ALWAYS_INLINE raw_ref& operator=(const raw_ref& p) noexcept {
  76. CHECK(p.inner_.get()); // Catch use-after-move.
  77. inner_.operator=(p.inner_);
  78. return *this;
  79. }
  80. ALWAYS_INLINE raw_ref& operator=(raw_ref&& p) noexcept {
  81. CHECK(p.inner_.get()); // Catch use-after-move.
  82. inner_.operator=(std::move(p.inner_));
  83. if constexpr (need_clear_after_move)
  84. p.inner_ = nullptr;
  85. return *this;
  86. }
  87. // Deliberately implicit in order to support implicit upcast.
  88. template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
  89. // NOLINTNEXTLINE(google-explicit-constructor)
  90. ALWAYS_INLINE raw_ref(const raw_ref<U, Impl>& p) noexcept : inner_(p.inner_) {
  91. CHECK(inner_.get()); // Catch use-after-move.
  92. }
  93. // Deliberately implicit in order to support implicit upcast.
  94. template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
  95. // NOLINTNEXTLINE(google-explicit-constructor)
  96. ALWAYS_INLINE raw_ref(raw_ref<U, Impl>&& p) noexcept
  97. : inner_(std::move(p.inner_)) {
  98. CHECK(inner_.get()); // Catch use-after-move.
  99. if constexpr (need_clear_after_move)
  100. p.inner_ = nullptr;
  101. }
  102. // Upcast assignment
  103. template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
  104. ALWAYS_INLINE raw_ref& operator=(const raw_ref<U, Impl>& p) noexcept {
  105. CHECK(p.inner_.get()); // Catch use-after-move.
  106. inner_.operator=(p.inner_);
  107. return *this;
  108. }
  109. template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
  110. ALWAYS_INLINE raw_ref& operator=(raw_ref<U, Impl>&& p) noexcept {
  111. CHECK(p.inner_.get()); // Catch use-after-move.
  112. inner_.operator=(std::move(p.inner_));
  113. if constexpr (need_clear_after_move)
  114. p.inner_ = nullptr;
  115. return *this;
  116. }
  117. ALWAYS_INLINE T& operator*() const {
  118. CHECK(inner_.get()); // Catch use-after-move.
  119. return inner_.operator*();
  120. }
  121. ALWAYS_INLINE T* operator->() const ABSL_ATTRIBUTE_RETURNS_NONNULL {
  122. CHECK(inner_.get()); // Catch use-after-move.
  123. return inner_.operator->();
  124. }
  125. friend ALWAYS_INLINE void swap(raw_ref& lhs, raw_ref& rhs) noexcept {
  126. CHECK(lhs.inner_.get()); // Catch use-after-move.
  127. CHECK(rhs.inner_.get()); // Catch use-after-move.
  128. swap(lhs.inner_, rhs.inner_);
  129. }
  130. // If T can be serialised into trace, its alias is also
  131. // serialisable.
  132. template <class U = T>
  133. typename perfetto::check_traced_value_support<U>::type WriteIntoTrace(
  134. perfetto::TracedValue&& context) const {
  135. CHECK(inner_.get()); // Catch use-after-move.
  136. inner_.WriteIntoTrace(std::move(context));
  137. }
  138. template <class U>
  139. friend ALWAYS_INLINE bool operator==(const raw_ref& lhs,
  140. const raw_ref<U, Impl>& rhs) {
  141. CHECK(lhs.inner_.get()); // Catch use-after-move.
  142. CHECK(rhs.inner_.get()); // Catch use-after-move.
  143. return lhs.inner_ == rhs.inner_;
  144. }
  145. template <class U>
  146. friend ALWAYS_INLINE bool operator!=(const raw_ref& lhs,
  147. const raw_ref<U, Impl>& rhs) {
  148. CHECK(lhs.inner_.get()); // Catch use-after-move.
  149. CHECK(rhs.inner_.get()); // Catch use-after-move.
  150. return lhs.inner_ != rhs.inner_;
  151. }
  152. template <class U>
  153. friend ALWAYS_INLINE bool operator<(const raw_ref& lhs,
  154. const raw_ref<U, Impl>& rhs) {
  155. CHECK(lhs.inner_.get()); // Catch use-after-move.
  156. CHECK(rhs.inner_.get()); // Catch use-after-move.
  157. return lhs.inner_ < rhs.inner_;
  158. }
  159. template <class U>
  160. friend ALWAYS_INLINE bool operator>(const raw_ref& lhs,
  161. const raw_ref<U, Impl>& rhs) {
  162. CHECK(lhs.inner_.get()); // Catch use-after-move.
  163. CHECK(rhs.inner_.get()); // Catch use-after-move.
  164. return lhs.inner_ > rhs.inner_;
  165. }
  166. template <class U>
  167. friend ALWAYS_INLINE bool operator<=(const raw_ref& lhs,
  168. const raw_ref<U, Impl>& rhs) {
  169. CHECK(lhs.inner_.get()); // Catch use-after-move.
  170. CHECK(rhs.inner_.get()); // Catch use-after-move.
  171. return lhs.inner_ <= rhs.inner_;
  172. }
  173. template <class U>
  174. friend ALWAYS_INLINE bool operator>=(const raw_ref& lhs,
  175. const raw_ref<U, Impl>& rhs) {
  176. CHECK(lhs.inner_.get()); // Catch use-after-move.
  177. CHECK(rhs.inner_.get()); // Catch use-after-move.
  178. return lhs.inner_ >= rhs.inner_;
  179. }
  180. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  181. friend ALWAYS_INLINE bool operator==(const raw_ref& lhs, const U& rhs) {
  182. CHECK(lhs.inner_.get()); // Catch use-after-move.
  183. return lhs.inner_ == &rhs;
  184. }
  185. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  186. friend ALWAYS_INLINE bool operator!=(const raw_ref& lhs, const U& rhs) {
  187. CHECK(lhs.inner_.get()); // Catch use-after-move.
  188. return lhs.inner_ != &rhs;
  189. }
  190. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  191. friend ALWAYS_INLINE bool operator<(const raw_ref& lhs, const U& rhs) {
  192. CHECK(lhs.inner_.get()); // Catch use-after-move.
  193. return lhs.inner_ < &rhs;
  194. }
  195. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  196. friend ALWAYS_INLINE bool operator>(const raw_ref& lhs, const U& rhs) {
  197. CHECK(lhs.inner_.get()); // Catch use-after-move.
  198. return lhs.inner_ > &rhs;
  199. }
  200. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  201. friend ALWAYS_INLINE bool operator<=(const raw_ref& lhs, const U& rhs) {
  202. CHECK(lhs.inner_.get()); // Catch use-after-move.
  203. return lhs.inner_ <= &rhs;
  204. }
  205. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  206. friend ALWAYS_INLINE bool operator>=(const raw_ref& lhs, const U& rhs) {
  207. CHECK(lhs.inner_.get()); // Catch use-after-move.
  208. return lhs.inner_ >= &rhs;
  209. }
  210. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  211. friend ALWAYS_INLINE bool operator==(const U& lhs, const raw_ref& rhs) {
  212. CHECK(rhs.inner_.get()); // Catch use-after-move.
  213. return &lhs == rhs.inner_;
  214. }
  215. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  216. friend ALWAYS_INLINE bool operator!=(const U& lhs, const raw_ref& rhs) {
  217. CHECK(rhs.inner_.get()); // Catch use-after-move.
  218. return &lhs != rhs.inner_;
  219. }
  220. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  221. friend ALWAYS_INLINE bool operator<(const U& lhs, const raw_ref& rhs) {
  222. CHECK(rhs.inner_.get()); // Catch use-after-move.
  223. return &lhs < rhs.inner_;
  224. }
  225. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  226. friend ALWAYS_INLINE bool operator>(const U& lhs, const raw_ref& rhs) {
  227. CHECK(rhs.inner_.get()); // Catch use-after-move.
  228. return &lhs > rhs.inner_;
  229. }
  230. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  231. friend ALWAYS_INLINE bool operator<=(const U& lhs, const raw_ref& rhs) {
  232. CHECK(rhs.inner_.get()); // Catch use-after-move.
  233. return &lhs <= rhs.inner_;
  234. }
  235. template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
  236. friend ALWAYS_INLINE bool operator>=(const U& lhs, const raw_ref& rhs) {
  237. CHECK(rhs.inner_.get()); // Catch use-after-move.
  238. return &lhs >= rhs.inner_;
  239. }
  240. private:
  241. template <class U, class J>
  242. friend class raw_ref;
  243. Inner inner_;
  244. };
  245. // CTAD deduction guide.
  246. template <class T>
  247. raw_ref(T) -> raw_ref<T>;
  248. // Template helpers for working with raw_ref<T>.
  249. template <typename T>
  250. struct IsRawRef : std::false_type {};
  251. template <typename T, typename I>
  252. struct IsRawRef<raw_ref<T, I>> : std::true_type {};
  253. template <typename T>
  254. inline constexpr bool IsRawRefV = IsRawRef<T>::value;
  255. template <typename T>
  256. struct RemoveRawRef {
  257. using type = T;
  258. };
  259. template <typename T, typename I>
  260. struct RemoveRawRef<raw_ref<T, I>> {
  261. using type = T;
  262. };
  263. template <typename T>
  264. using RemoveRawRefT = typename RemoveRawRef<T>::type;
  265. } // namespace base
  266. using base::raw_ref;
  267. namespace std {
  268. // Override so set/map lookups do not create extra raw_ref. This also
  269. // allows C++ references to be used for lookup.
  270. template <typename T, typename Impl>
  271. struct less<raw_ref<T, Impl>> {
  272. using is_transparent = void;
  273. bool operator()(const raw_ref<T, Impl>& lhs,
  274. const raw_ref<T, Impl>& rhs) const {
  275. Impl::IncrementLessCountForTest();
  276. return lhs < rhs;
  277. }
  278. bool operator()(T& lhs, const raw_ref<T, Impl>& rhs) const {
  279. Impl::IncrementLessCountForTest();
  280. return lhs < rhs;
  281. }
  282. bool operator()(const raw_ref<T, Impl>& lhs, T& rhs) const {
  283. Impl::IncrementLessCountForTest();
  284. return lhs < rhs;
  285. }
  286. };
  287. } // namespace std
  288. #endif // BASE_MEMORY_RAW_REF_H_