123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- // Copyright 2022 The Chromium 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 BASE_MEMORY_RAW_REF_H_
- #define BASE_MEMORY_RAW_REF_H_
- #include <memory>
- #include <type_traits>
- #include <utility>
- #include "base/compiler_specific.h"
- #include "base/memory/raw_ptr.h"
- #include "third_party/abseil-cpp/absl/base/attributes.h"
- namespace base {
- template <class T, class Impl>
- class raw_ref;
- namespace internal {
- template <class T>
- struct is_raw_ref : std::false_type {};
- template <class T, class I>
- struct is_raw_ref<::base::raw_ref<T, I>> : std::true_type {};
- template <class T>
- constexpr inline bool is_raw_ref_v = is_raw_ref<T>::value;
- } // namespace internal
- // A smart pointer for a pointer which can not be null, and which provides
- // Use-after-Free protection in the same ways as raw_ptr. This class acts like a
- // combination of std::reference_wrapper and raw_ptr.
- //
- // See raw_ptr and //base/memory/raw_ptr.md for more details on the
- // Use-after-Free protection.
- //
- // # Use after move
- //
- // The raw_ref type will abort if used after being moved.
- //
- // # Constness
- //
- // Use a `const raw_ref<T>` when the smart pointer should not be able to rebind
- // to a new reference. Use a `const raw_ref<const T>` do the same for a const
- // reference, which is like `const T&`.
- //
- // Unlike a native `T&` reference, a mutable `raw_ref<T>` can be changed
- // independent of the underlying `T`, similar to `std::reference_wrapper`. That
- // means the reference inside it can be moved and reassigned.
- template <class T, class Impl = DefaultRawPtrImpl>
- class TRIVIAL_ABI GSL_POINTER raw_ref {
- using Inner = raw_ptr<T, Impl>;
- // These impls do not clear on move, which produces an inconsistent behaviour.
- // We want consistent behaviour such that using a raw_ref after move is caught
- // and aborts. Failure to clear would be indicated by the related death tests
- // not CHECKing appropriately.
- static constexpr bool need_clear_after_move =
- std::is_same_v<Impl, internal::RawPtrNoOpImpl> ||
- #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
- std::is_same_v<Impl,
- internal::MTECheckedPtrImpl<
- internal::MTECheckedPtrImplPartitionAllocSupport>> ||
- #endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
- std::is_same_v<Impl, internal::AsanBackupRefPtrImpl>;
- public:
- ALWAYS_INLINE explicit raw_ref(T& p) noexcept : inner_(std::addressof(p)) {}
- ALWAYS_INLINE raw_ref& operator=(T& p) noexcept {
- inner_.operator=(&p);
- return *this;
- }
- // Disallow holding references to temporaries.
- raw_ref(const T&& p) = delete;
- raw_ref& operator=(const T&& p) = delete;
- ALWAYS_INLINE raw_ref(const raw_ref& p) noexcept : inner_(p.inner_) {
- CHECK(inner_.get()); // Catch use-after-move.
- }
- ALWAYS_INLINE raw_ref(raw_ref&& p) noexcept : inner_(std::move(p.inner_)) {
- CHECK(inner_.get()); // Catch use-after-move.
- if constexpr (need_clear_after_move)
- p.inner_ = nullptr;
- }
- ALWAYS_INLINE raw_ref& operator=(const raw_ref& p) noexcept {
- CHECK(p.inner_.get()); // Catch use-after-move.
- inner_.operator=(p.inner_);
- return *this;
- }
- ALWAYS_INLINE raw_ref& operator=(raw_ref&& p) noexcept {
- CHECK(p.inner_.get()); // Catch use-after-move.
- inner_.operator=(std::move(p.inner_));
- if constexpr (need_clear_after_move)
- p.inner_ = nullptr;
- return *this;
- }
- // Deliberately implicit in order to support implicit upcast.
- template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
- // NOLINTNEXTLINE(google-explicit-constructor)
- ALWAYS_INLINE raw_ref(const raw_ref<U, Impl>& p) noexcept : inner_(p.inner_) {
- CHECK(inner_.get()); // Catch use-after-move.
- }
- // Deliberately implicit in order to support implicit upcast.
- template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
- // NOLINTNEXTLINE(google-explicit-constructor)
- ALWAYS_INLINE raw_ref(raw_ref<U, Impl>&& p) noexcept
- : inner_(std::move(p.inner_)) {
- CHECK(inner_.get()); // Catch use-after-move.
- if constexpr (need_clear_after_move)
- p.inner_ = nullptr;
- }
- // Upcast assignment
- template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
- ALWAYS_INLINE raw_ref& operator=(const raw_ref<U, Impl>& p) noexcept {
- CHECK(p.inner_.get()); // Catch use-after-move.
- inner_.operator=(p.inner_);
- return *this;
- }
- template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
- ALWAYS_INLINE raw_ref& operator=(raw_ref<U, Impl>&& p) noexcept {
- CHECK(p.inner_.get()); // Catch use-after-move.
- inner_.operator=(std::move(p.inner_));
- if constexpr (need_clear_after_move)
- p.inner_ = nullptr;
- return *this;
- }
- ALWAYS_INLINE T& operator*() const {
- CHECK(inner_.get()); // Catch use-after-move.
- return inner_.operator*();
- }
- ALWAYS_INLINE T* operator->() const ABSL_ATTRIBUTE_RETURNS_NONNULL {
- CHECK(inner_.get()); // Catch use-after-move.
- return inner_.operator->();
- }
- friend ALWAYS_INLINE void swap(raw_ref& lhs, raw_ref& rhs) noexcept {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- swap(lhs.inner_, rhs.inner_);
- }
- // If T can be serialised into trace, its alias is also
- // serialisable.
- template <class U = T>
- typename perfetto::check_traced_value_support<U>::type WriteIntoTrace(
- perfetto::TracedValue&& context) const {
- CHECK(inner_.get()); // Catch use-after-move.
- inner_.WriteIntoTrace(std::move(context));
- }
- template <class U>
- friend ALWAYS_INLINE bool operator==(const raw_ref& lhs,
- const raw_ref<U, Impl>& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ == rhs.inner_;
- }
- template <class U>
- friend ALWAYS_INLINE bool operator!=(const raw_ref& lhs,
- const raw_ref<U, Impl>& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ != rhs.inner_;
- }
- template <class U>
- friend ALWAYS_INLINE bool operator<(const raw_ref& lhs,
- const raw_ref<U, Impl>& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ < rhs.inner_;
- }
- template <class U>
- friend ALWAYS_INLINE bool operator>(const raw_ref& lhs,
- const raw_ref<U, Impl>& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ > rhs.inner_;
- }
- template <class U>
- friend ALWAYS_INLINE bool operator<=(const raw_ref& lhs,
- const raw_ref<U, Impl>& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ <= rhs.inner_;
- }
- template <class U>
- friend ALWAYS_INLINE bool operator>=(const raw_ref& lhs,
- const raw_ref<U, Impl>& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ >= rhs.inner_;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator==(const raw_ref& lhs, const U& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ == &rhs;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator!=(const raw_ref& lhs, const U& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ != &rhs;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator<(const raw_ref& lhs, const U& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ < &rhs;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator>(const raw_ref& lhs, const U& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ > &rhs;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator<=(const raw_ref& lhs, const U& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ <= &rhs;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator>=(const raw_ref& lhs, const U& rhs) {
- CHECK(lhs.inner_.get()); // Catch use-after-move.
- return lhs.inner_ >= &rhs;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator==(const U& lhs, const raw_ref& rhs) {
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return &lhs == rhs.inner_;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator!=(const U& lhs, const raw_ref& rhs) {
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return &lhs != rhs.inner_;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator<(const U& lhs, const raw_ref& rhs) {
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return &lhs < rhs.inner_;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator>(const U& lhs, const raw_ref& rhs) {
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return &lhs > rhs.inner_;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator<=(const U& lhs, const raw_ref& rhs) {
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return &lhs <= rhs.inner_;
- }
- template <class U, class = std::enable_if_t<!internal::is_raw_ref_v<U>, void>>
- friend ALWAYS_INLINE bool operator>=(const U& lhs, const raw_ref& rhs) {
- CHECK(rhs.inner_.get()); // Catch use-after-move.
- return &lhs >= rhs.inner_;
- }
- private:
- template <class U, class J>
- friend class raw_ref;
- Inner inner_;
- };
- // CTAD deduction guide.
- template <class T>
- raw_ref(T) -> raw_ref<T>;
- // Template helpers for working with raw_ref<T>.
- template <typename T>
- struct IsRawRef : std::false_type {};
- template <typename T, typename I>
- struct IsRawRef<raw_ref<T, I>> : std::true_type {};
- template <typename T>
- inline constexpr bool IsRawRefV = IsRawRef<T>::value;
- template <typename T>
- struct RemoveRawRef {
- using type = T;
- };
- template <typename T, typename I>
- struct RemoveRawRef<raw_ref<T, I>> {
- using type = T;
- };
- template <typename T>
- using RemoveRawRefT = typename RemoveRawRef<T>::type;
- } // namespace base
- using base::raw_ref;
- namespace std {
- // Override so set/map lookups do not create extra raw_ref. This also
- // allows C++ references to be used for lookup.
- template <typename T, typename Impl>
- struct less<raw_ref<T, Impl>> {
- using is_transparent = void;
- bool operator()(const raw_ref<T, Impl>& lhs,
- const raw_ref<T, Impl>& rhs) const {
- Impl::IncrementLessCountForTest();
- return lhs < rhs;
- }
- bool operator()(T& lhs, const raw_ref<T, Impl>& rhs) const {
- Impl::IncrementLessCountForTest();
- return lhs < rhs;
- }
- bool operator()(const raw_ref<T, Impl>& lhs, T& rhs) const {
- Impl::IncrementLessCountForTest();
- return lhs < rhs;
- }
- };
- } // namespace std
- #endif // BASE_MEMORY_RAW_REF_H_
|