chromium/base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr.h

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// IWYU pragma: private, include "base/memory/raw_ptr.h"

#ifndef PARTITION_ALLOC_POINTERS_RAW_PTR_H_
#define PARTITION_ALLOC_POINTERS_RAW_PTR_H_

#include <cstddef>
#include <cstdint>
#include <functional>
#include <type_traits>
#include <utility>

#include "partition_alloc/build_config.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/flags.h"
#include "partition_alloc/partition_alloc_base/compiler_specific.h"
#include "partition_alloc/partition_alloc_base/component_export.h"
#include "partition_alloc/partition_alloc_base/cxx20_is_constant_evaluated.h"
#include "partition_alloc/partition_alloc_config.h"
#include "partition_alloc/partition_alloc_forward.h"
#include "partition_alloc/pointers/instance_tracer.h"

#if PA_BUILDFLAG(IS_WIN)
#include "partition_alloc/partition_alloc_base/win/win_handle_types.h"
#endif

#if PA_BUILDFLAG(USE_PARTITION_ALLOC)
#include "partition_alloc/partition_alloc_base/check.h"
// Live implementation of MiraclePtr being built.
#if PA_BUILDFLAG(USE_RAW_PTR_BACKUP_REF_IMPL) || \
    PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
#define PA_RAW_PTR_CHECK(condition)
#else
// No-op implementation of MiraclePtr being built.
// Note that `PA_BASE_DCHECK()` evaporates from non-DCHECK builds,
// minimizing impact of generated code.
#define PA_RAW_PTR_CHECK
#endif  // PA_BUILDFLAG(USE_RAW_PTR_BACKUP_REF_IMPL) ||
        // PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
#else   // PA_BUILDFLAG(USE_PARTITION_ALLOC)
// Without PartitionAlloc, there's no `PA_BASE_D?CHECK()` implementation
// available.
#define PA_RAW_PTR_CHECK
#endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC)

#if PA_BUILDFLAG(USE_RAW_PTR_BACKUP_REF_IMPL)
#include "partition_alloc/pointers/raw_ptr_backup_ref_impl.h"
#elif PA_BUILDFLAG(USE_RAW_PTR_ASAN_UNOWNED_IMPL)
#include "partition_alloc/pointers/raw_ptr_asan_unowned_impl.h"
#elif PA_BUILDFLAG(USE_RAW_PTR_HOOKABLE_IMPL)
#include "partition_alloc/pointers/raw_ptr_hookable_impl.h"
#else
#include "partition_alloc/pointers/raw_ptr_noop_impl.h"
#endif

namespace cc {
class ImageDecodeCache;
class Scheduler;
class TextureLayerImpl;
}  // namespace cc
namespace gpu {
class SchedulerDfs;
}
namespace base::internal {
class DelayTimerBase;
class JobTaskSource;
}
namespace base::test {
struct RawPtrCountingImplForTest;
}
namespace content::responsiveness {
class Calculator;
}
namespace v8 {
class JobTask;
}
namespace blink::scheduler {
class MainThreadTaskQueue;
class NonMainThreadTaskQueue;
}  // namespace blink::scheduler
namespace base::sequence_manager::internal {
class TaskQueueImpl;
}
namespace mojo {
class Connector;
}

namespace partition_allocinternal  // namespace partition_alloc::internal

namespace base {
RawPtrTraits;

namespace raw_ptr_traits {

// IsSupportedType<T>::value answers whether raw_ptr<T>:
//   1) compiles
//   2) is safe at runtime
//
// Templates that may end up using raw_ptr should use IsSupportedType to ensure
// that raw_ptr is not used with unsupported types. As an example, see how
// base::internal::Unretained(Ref)Wrapper uses IsSupportedType to decide whether
// it should use `raw_ptr<T>` or `T*`.
template <typename T, typename SFINAE = void>
struct IsSupportedType {};

// raw_ptr<T> is not compatible with function pointer types. Also, they don't
// even need the raw_ptr protection, because they don't point on heap.
IsSupportedType<T, std::enable_if_t<std::is_function_v<T>>>;

// This section excludes some types from raw_ptr<T> to avoid them from being
// used inside base::Unretained in performance sensitive places.
// The ones below were identified from sampling profiler data. See
// crbug.com/1287151 for more info.
template <>
struct IsSupportedType<cc::Scheduler> {};
template <>
struct IsSupportedType<base::internal::DelayTimerBase> {};
template <>
struct IsSupportedType<content::responsiveness::Calculator> {};
// The ones below were identified from speedometer3. See crbug.com/335556942 for
// more info.
template <>
struct IsSupportedType<v8::JobTask> {};
template <>
struct IsSupportedType<blink::scheduler::MainThreadTaskQueue> {};
template <>
struct IsSupportedType<base::sequence_manager::internal::TaskQueueImpl> {};
template <>
struct IsSupportedType<base::internal::JobTaskSource> {};
template <>
struct IsSupportedType<mojo::Connector> {};
template <>
struct IsSupportedType<blink::scheduler::NonMainThreadTaskQueue> {};
// The ones below were identified from MotionMark. See crbug.com/335556942 for
// more info.
template <>
struct IsSupportedType<cc::ImageDecodeCache> {};
template <>
struct IsSupportedType<cc::TextureLayerImpl> {};
template <>
struct IsSupportedType<gpu::SchedulerDfs> {};

#if __OBJC__
// raw_ptr<T> is not compatible with pointers to Objective-C classes for a
// multitude of reasons. They may fail to compile in many cases, and wouldn't
// work well with tagged pointers. Anyway, Objective-C objects have their own
// way of tracking lifespan, hence don't need the raw_ptr protection as much.
//
// Such pointers are detected by checking if they're convertible to |id| type.
template <typename T>
struct IsSupportedType<T, std::enable_if_t<std::is_convertible_v<T*, id>>> {
  static constexpr bool value = false;
};
#endif  // __OBJC__

#if PA_BUILDFLAG(IS_WIN)
// raw_ptr<HWND__> is unsafe at runtime - if the handle happens to also
// represent a valid pointer into a PartitionAlloc-managed region then it can
// lead to manipulating random memory when treating it as BackupRefPtr
// ref-count.  See also https://crbug.com/1262017.
//
// TODO(crbug.com/40799223): Cover other handle types like HANDLE,
// HLOCAL, HINTERNET, or HDEVINFO.  Maybe we should avoid using raw_ptr<T> when
// T=void (as is the case in these handle types).  OTOH, explicit,
// non-template-based raw_ptr<void> should be allowed.  Maybe this can be solved
// by having 2 traits: IsPointeeAlwaysSafe (to be used in templates) and
// IsPointeeUsuallySafe (to be used in the static_assert in raw_ptr).  The
// upside of this approach is that it will safely handle base::Bind closing over
// HANDLE.  The downside of this approach is that base::Bind closing over a
// void* pointer will not get UaF protection.
#define PA_WINDOWS_HANDLE_TYPE
#include "partition_alloc/partition_alloc_base/win/win_handle_types_list.inc"
#undef PA_WINDOWS_HANDLE_TYPE
#endif

#if PA_BUILDFLAG(USE_RAW_PTR_BACKUP_REF_IMPL)
UnderlyingImplForTraits;

#elif PA_BUILDFLAG(USE_RAW_PTR_ASAN_UNOWNED_IMPL)
template <RawPtrTraits Traits>
using UnderlyingImplForTraits = internal::RawPtrAsanUnownedImpl<
    partition_alloc::internal::ContainsFlags(Traits,
                                             RawPtrTraits::kAllowPtrArithmetic),
    partition_alloc::internal::ContainsFlags(Traits, RawPtrTraits::kMayDangle)>;

#elif PA_BUILDFLAG(USE_RAW_PTR_HOOKABLE_IMPL)
template <RawPtrTraits Traits>
using UnderlyingImplForTraits = internal::RawPtrHookableImpl<
    /*EnableHooks=*/!partition_alloc::internal::ContainsFlags(
        Traits,
        RawPtrTraits::kDisableHooks)>;

#else
template <RawPtrTraits Traits>
using UnderlyingImplForTraits = internal::RawPtrNoOpImpl;
#endif

constexpr bool IsPtrArithmeticAllowed([[maybe_unused]] RawPtrTraits Traits) {}

// ImplForTraits is the struct that implements raw_ptr functions. Think of
// raw_ptr as a thin wrapper, that directs calls to ImplForTraits. ImplForTraits
// may be different from UnderlyingImplForTraits, because it may select a
// test impl instead.
ImplForTraits;

// `kTypeTraits` is a customization interface to accosiate `T` with some
// `RawPtrTraits`. Users may create specialization of this variable
// to enable some traits by default.
// Note that specialization must be declared before the first use that would
// cause implicit instantiation of `raw_ptr` or `raw_ref`, in every translation
// unit where such use occurs.
kTypeTraits;

}  // namespace raw_ptr_traits

// `raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety
// over raw pointers. See the documentation for details:
// https://source.chromium.org/chromium/chromium/src/+/main:base/memory/raw_ptr.md
//
// raw_ptr<T> is marked as [[gsl::Pointer]] which allows the compiler to catch
// some bugs where the raw_ptr holds a dangling pointer to a temporary object.
// However the [[gsl::Pointer]] analysis expects that such types do not have a
// non-default move constructor/assignment. Thus, it's possible to get an error
// where the pointer is not actually dangling, and have to work around the
// compiler. We have not managed to construct such an example in Chromium yet.
template <typename T, RawPtrTraits PointerTraits = RawPtrTraits::kEmpty>
class PA_TRIVIAL_ABI PA_GSL_POINTER raw_ptr {};

template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2>
PA_ALWAYS_INLINE constexpr bool operator==(const raw_ptr<U, Traits1>& lhs,
                                           const raw_ptr<V, Traits2>& rhs) {}

template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2>
PA_ALWAYS_INLINE constexpr bool operator!=(const raw_ptr<U, Traits1>& lhs,
                                           const raw_ptr<V, Traits2>& rhs) {}

template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2>
PA_ALWAYS_INLINE constexpr bool operator<(const raw_ptr<U, Traits1>& lhs,
                                          const raw_ptr<V, Traits2>& rhs) {}

template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2>
PA_ALWAYS_INLINE constexpr bool operator>(const raw_ptr<U, Traits1>& lhs,
                                          const raw_ptr<V, Traits2>& rhs) {}

template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2>
PA_ALWAYS_INLINE constexpr bool operator<=(const raw_ptr<U, Traits1>& lhs,
                                           const raw_ptr<V, Traits2>& rhs) {}

template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2>
PA_ALWAYS_INLINE constexpr bool operator>=(const raw_ptr<U, Traits1>& lhs,
                                           const raw_ptr<V, Traits2>& rhs) {}

template <typename T>
struct IsRawPtr : std::false_type {};

IsRawPtr<raw_ptr<T, Traits>>;

IsRawPtrV;

IsRawPtrMayDangleV;

IsRawPtrMayDangleV;

// Template helpers for working with T* or raw_ptr<T>.
template <typename T>
struct IsRawPointerHelper : std::false_type {};

IsRawPointerHelper<T *>;

IsRawPointerHelper<raw_ptr<T, Traits>>;

IsRawPointer;

template <typename T>
struct RemoveRawPointer {};

RemoveRawPointer<T *>;

RemoveRawPointer<raw_ptr<T, Traits>>;

RemoveRawPointerT;

}  // namespace base

raw_ptr;

// DisableDanglingPtrDetection option for raw_ptr annotates
// "intentional-and-safe" dangling pointers. It is meant to be used at the
// margin, only if there is no better way to re-architecture the code.
//
// Usage:
// raw_ptr<T, DisableDanglingPtrDetection> dangling_ptr;
//
// When using it, please provide a justification about what guarantees that it
// will never be dereferenced after becoming dangling.
constexpr inline auto DisableDanglingPtrDetection =;

// See `docs/dangling_ptr.md`
// Annotates known dangling raw_ptr. Those haven't been triaged yet. All the
// occurrences are meant to be removed. See https://crbug.com/1291138.
constexpr inline auto DanglingUntriaged =;

// Unlike DanglingUntriaged, this annotates raw_ptrs that are known to
// dangle only occasionally on the CQ.
//
// These were found from CQ runs and analysed in this dashboard:
// https://docs.google.com/spreadsheets/d/1k12PQOG4y1-UEV9xDfP1F8FSk4cVFywafEYHmzFubJ8/
//
// This is not meant to be added manually. You can ignore this flag.
constexpr inline auto FlakyDanglingUntriaged =;

// Dangling raw_ptr that is more likely to cause UAF: its memory was freed in
// one task, and the raw_ptr was released in a different one.
//
// This is not meant to be added manually. You can ignore this flag.
constexpr inline auto AcrossTasksDanglingUntriaged =;

// The use of pointer arithmetic with raw_ptr is strongly discouraged and
// disabled by default. Usually a container like span<> should be used
// instead of the raw_ptr.
constexpr inline auto AllowPtrArithmetic =;

// The use of uninitialized pointers is strongly discouraged. raw_ptrs will
// be initialized to nullptr by default in all cases when building against
// Chromium. However, third-party projects built in a standalone manner may
// wish to opt out where possible. One way to do this is via buildflags,
// thus affecting all raw_ptrs, but a finer-grained mechanism is the use
// of the kAllowUninitialized trait.
//
// Note that opting out may not always be effective, given that algorithms
// like BackupRefPtr require nullptr initializaion for correctness and thus
// silently enforce it.
constexpr inline auto AllowUninitialized =;

// This flag is used to tag a subset of dangling pointers. Similarly to
// DanglingUntriaged, those pointers are known to be dangling. However, we also
// detected that those raw_ptr's were never released (either by calling
// raw_ptr's destructor or by resetting its value), which can ultimately put
// pressure on the BRP quarantine.
//
// This is not meant to be added manually. You can ignore this flag.
constexpr inline auto LeakedDanglingUntriaged =;

// Temporary introduced alias in the context of rewriting std::vector<T*> into
// std::vector<raw_ptr<T>> and in order to temporarily bypass the dangling ptr
// checks on the CQ. This alias will be removed gradually after the cl lands and
// will be replaced by DanglingUntriaged where necessary.
constexpr inline auto VectorExperimental =;

// Temporary alias introduced in the context of rewriting std::set<T*> into
// std::set<raw_ptr<T>> and in order to temporarily bypass the dangling ptr
// checks on the CQ. This alias will be removed gradually after the rewrite cl
// lands and will be replaced by DanglingUntriaged where necessary.
constexpr inline auto SetExperimental =;

// Temporary alias introduced in the context of rewriting more containers and in
// order to temporarily bypass the dangling ptr checks on the CQ. This alias
// will be removed gradually after the rewrite cl lands and will be replaced by
// DanglingUntriaged where necessary.
constexpr inline auto CtnExperimental =;

// Public verson used in callbacks arguments when it is known that they might
// receive dangling pointers. In any other cases, please
// use one of:
// - raw_ptr<T, DanglingUntriaged>
// - raw_ptr<T, DisableDanglingPtrDetection>
MayBeDangling;

namespace std {

// Override so set/map lookups do not create extra raw_ptr. This also allows
// dangling pointers to be used for lookup.
less<raw_ptr<T, Traits>>;

hash<raw_ptr<T, Traits>>;

// Define for cases where raw_ptr<T> holds a pointer to an array of type T.
// This is consistent with definition of std::iterator_traits<T*>.
// Algorithms like std::binary_search need that.
iterator_traits<raw_ptr<T, Traits>>;

// Specialize std::pointer_traits. The latter is required to obtain the
// underlying raw pointer in the std::to_address(pointer) overload.
// Implementing the pointer_traits is the standard blessed way to customize
// `std::to_address(pointer)` in C++20 [3].
//
// [1] https://wg21.link/pointer.traits.optmem
pointer_traits< ::raw_ptr<T, Traits>>;

}  // namespace std

#endif  // PARTITION_ALLOC_POINTERS_RAW_PTR_H_