• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 #ifndef BASE_MEMORY_RAW_PTR_ASAN_BOUND_ARG_TRACKER_H_
6 #define BASE_MEMORY_RAW_PTR_ASAN_BOUND_ARG_TRACKER_H_
7 
8 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
9 
10 #if BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
11 #include <cstddef>
12 #include <cstdint>
13 #include <memory>
14 #include <vector>
15 
16 #include "base/base_export.h"
17 #include "base/containers/stack_container.h"
18 #include "base/memory/raw_ptr.h"
19 
20 namespace base {
21 namespace internal {
22 template <typename, typename>
23 struct Invoker;
24 
25 template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
26 class UnretainedWrapper;
27 
28 template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
29 class UnretainedRefWrapper;
30 }  // namespace internal
31 
32 // Tracks the lifetimes of bound pointer arguments during callback invocation.
33 //
34 // Example:
35 //   T* unsafe_ptr = new T();
36 //   PostTask(base::BindOnce(&T::DoSomething, base::Unretained(unsafe_ptr)));
37 //   delete unsafe_ptr;
38 //
39 // When the callback executes, the callee has no access to the raw_ptr<T> inside
40 // base::Unretained, so it is not possible for it to be invalidated until the
41 // callback finishes execution; so there is always at least one live raw_ptr<T>
42 // pointing to `this` for the duration of the call to T::DoSomething.
43 //
44 // This class is responsible for tracking and checking which allocations are
45 // currently protected in this way, and it is only intended to be used inside
46 // the Bind implementation. This should not be used directly.
47 class BASE_EXPORT RawPtrAsanBoundArgTracker {
48  public:
49   static constexpr size_t kInlineArgsCount = 3;
50   using ProtectedArgsVector = base::StackVector<uintptr_t, kInlineArgsCount>;
51 
52   // Check whether ptr is an address inside an allocation pointed to by one of
53   // the currently protected callback arguments. If it is, then this function
54   // returns the base address of that allocation, otherwise it returns 0.
55   static uintptr_t GetProtectedArgPtr(uintptr_t ptr);
56 
57  private:
58   template <typename, typename>
59   friend struct internal::Invoker;
60 
61   void Add(uintptr_t pointer);
62 
63   RawPtrAsanBoundArgTracker();
64   ~RawPtrAsanBoundArgTracker();
65 
66   // Base case for any type that isn't base::Unretained, we do nothing.
67   template <typename T>
AddArg(const T & arg)68   void AddArg(const T& arg) {}
69 
70   // No specialization for raw_ptr<T> directly, since bound raw_ptr<T>
71   // arguments are stored in UnretainedWrapper.
72 
73   // When argument is base::Unretained, add the argument to the set of
74   // arguments protected in this scope.
75   template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
AddArg(const internal::UnretainedWrapper<T,UnretainedTrait,PtrTraits> & arg)76   void AddArg(
77       const internal::UnretainedWrapper<T, UnretainedTrait, PtrTraits>& arg) {
78     if constexpr (raw_ptr_traits::IsSupportedType<T>::value) {
79       auto inner = arg.get();
80       // The argument may unwrap into a raw_ptr or a T* depending if it is
81       // allowed to dangle.
82       if constexpr (IsRawPtrV<decltype(inner)>) {
83         Add(reinterpret_cast<uintptr_t>(inner.get()));
84       } else {
85         Add(reinterpret_cast<uintptr_t>(inner));
86       }
87     }
88   }
89 
90   // When argument is a reference type that's supported by raw_ptr, add the
91   // argument to the set of arguments protected in this scope.
92   template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
AddArg(const internal::UnretainedRefWrapper<T,UnretainedTrait,PtrTraits> & arg)93   void AddArg(
94       const internal::UnretainedRefWrapper<T, UnretainedTrait, PtrTraits>&
95           arg) {
96     if constexpr (raw_ptr_traits::IsSupportedType<T>::value) {
97       Add(reinterpret_cast<uintptr_t>(&arg.get()));
98     }
99   }
100 
101   template <typename... Args>
AddArgs(Args &&...args)102   void AddArgs(Args&&... args) {
103     if (enabled_) {
104       (AddArg(std::forward<Args>(args)), ...);
105     }
106   }
107 
108   // Cache whether or not BRP-ASan is running when we enter the argument
109   // tracking scope so that we ensure that our actions on leaving the scope are
110   // consistent even if the runtime flags are changed.
111   bool enabled_;
112 
113   // We save the previously bound arguments, so that we can restore them when
114   // this callback returns. This helps with coverage while avoiding false
115   // positives due to nested run loops/callback re-entrancy.
116   raw_ptr<ProtectedArgsVector> prev_protected_args_;
117   ProtectedArgsVector protected_args_;
118 };
119 
120 }  // namespace base
121 
122 #endif  // BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
123 #endif  // BASE_MEMORY_RAW_PTR_ASAN_BOUND_ARG_TRACKER_H_
124