// 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_