• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# raw_ptr<T> (aka. MiraclePtr, aka. BackupRefPtr, aka. BRP)
2
3## Quick rules
4
5Before telling you what `raw_ptr<T>` is, we'd like you to follow one simple
6rule: think of it as a raw C++ pointer. In particular:
7- Initialize it yourself, don't assume the constructor default-initializes it
8  (it may or may not). (Always use the `raw_ptr<T> member_ = nullptr;` form of
9  initialization rather than the so-called uniform initialization form
10  (empty braces) `raw_ptr<T> member_{};` whose meaning varies with the
11  implementation.)
12- Don't assume that moving clears the pointer (it may or may not).
13- The owner of the memory must free it when the time is right, don't assume
14  `raw_ptr<T>` will free it for  you (it won't). Unlike `std::unique_ptr<T>`,
15  `base::scoped_refptr<T>`, etc., it does not manage ownership or lifetime of
16  an allocated object.
17  - if the pointer is the owner of the memory, consider using an alternative
18    smart pointer.
19- Don't assume `raw_ptr<T>` will protect you from freeing memory too early (it
20  likely will, but there are gotchas; one of them is that dereferencing will
21  result in other type of undefined behavior).
22
23(There are other, much more subtle rules that you should follow, but they're
24harder to accidentally violate, hence discussed in the further section
25["Extra pointer rules"](#Extra-pointer-rules).)
26
27## What is |raw_ptr&lt;T&gt;|
28
29`raw_ptr<T>` is a part of
30[the MiraclePtr project](https://docs.google.com/document/d/1pnnOAIz_DMWDI4oIOFoMAqLnf_MZ2GsrJNb_dbQ3ZBg/edit?usp=sharing)
31and currently implements
32[the BackupRefPtr algorithm](https://docs.google.com/document/d/1m0c63vXXLyGtIGBi9v6YFANum7-IRC3-dmiYBCWqkMk/edit?usp=sharing).
33If needed, please reach out to
34[memory-safety-dev@chromium.org](https://groups.google.com/a/chromium.org/g/memory-safety-dev)
35or (Google-internal)
36[chrome-memory-safety@google.com](https://groups.google.com/a/google.com/g/chrome-memory-safety)
37with questions or concerns.
38
39`raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety over
40raw pointers.  It behaves just like a raw pointer on platforms where
41USE_RAW_PTR_BACKUP_REF_IMPL is off, and almost like one when it's on. The main
42difference is that when USE_RAW_PTR_BACKUP_REF_IMPL is enabled, `raw_ptr<T>`
43is beneficial for security, because it can prevent a significant percentage of
44Use-after-Free (UaF) bugs from being exploitable. It achieves this by
45quarantining the freed memory as long as any dangling `raw_ptr<T>` pointing to
46it exists, and poisoning it (with
47[0xEF..EF](https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h;l=488;drc=b5a738b11528b81c4cc2d522bfac88716c8aac49)
48pattern).
49
50Note that the sheer act of dereferencing a dangling pointer won't
51crash, but poisoning increases chances that a subsequent usage of read memory
52will crash (particularly if the read poison is interpreted as a pointer and
53dereferenced thereafter), thus giving us a chance to investigate and fix.
54Having said that, we want to emphasize that dereferencing a dangling pointer
55remains an Undefined Behavior.
56
57`raw_ptr<T>` protection is enabled by default in all non-Renderer processes, on:
58- Android (incl. AndroidWebView, Android WebEngine, & Android ChromeCast)
59- Windows
60- ChromeOS (incl. Ash & Lacros)
61- macOS
62- Linux
63- Fuchsia
64
65In particular, it isn't yet enabled by default on:
66- iOS
67- Linux CastOS (Nest hardware)
68
69For the source of truth, both `enable_backup_ref_ptr_support` and `enable_backup_ref_ptr_feature_flag` need to enabled.
70Please refer to the following files: [build_overrides/partition_alloc.gni](https://source.chromium.org/chromium/chromium/src/+/main:build_overrides/partition_alloc.gni) and [partition_alloc.gni](https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/partition_alloc.gni;l=5?q=partition_alloc.gni&sq=&ss=chromium)
71
72
73[TOC]
74
75## When to use |raw_ptr&lt;T&gt;|
76
77[The Chromium C++ Style Guide](../../styleguide/c++/c++.md#non_owning-pointers-in-class-fields)
78asks to use `raw_ptr<T>` for class and struct fields in place of
79a raw C++ pointer `T*` whenever possible, except in Renderer-only code.
80This guide offers more details.
81
82The usage guidelines are currently enforced via Chromium Clang Plugin. We allow
83exclusions via:
84- `RAW_PTR_EXCLUSION` C++ attribute to exclude individual fields.  Examples:
85    - Cases where `raw_ptr<T>` won't compile (e.g. cases covered in
86      [the "Unsupported cases leading to compile errors" section](#Unsupported-cases-leading-to-compile-errors)).
87      Make sure to also look at
88      [the "Recoverable compile-time problems" section](#Recoverable-compile-time-problems).
89    - Cases where the pointer always points outside of PartitionAlloc
90      (e.g.  literals, stack allocated memory, shared memory, mmap'ed memory,
91      V8/Oilpan/Java heaps, TLS, etc.).
92    - (Very rare) cases that cause perf regression.
93    - (Very rare) cases where `raw_ptr<T>` can lead to runtime errors.
94      Make sure to look at
95      [the "Extra pointer rules" section](#Extra-pointer-rules)
96      before resorting to this exclusion.
97- [RawPtrManualPathsToIgnore.h](../../tools/clang/plugins/RawPtrManualPathsToIgnore.h)
98  to exclude at a directory level (NOTE, use it as last resort, and be aware
99  it'll require a Clang plugin roll).  Examples:
100    - Renderer-only code (i.e. code in paths that contain `/renderer/` or
101      `third_party/blink/public/web/`)
102    - Code that cannot depend on `//base`
103    - Code in `//ppapi`
104- No explicit exclusions are needed for:
105    - `const char*`, `const wchar_t*`, etc.
106    - Function pointers
107    - ObjC pointers
108
109## Examples of using |raw_ptr&lt;T&gt;| instead of raw C++ pointers
110
111Consider an example struct that uses raw C++ pointer fields:
112
113```cpp
114struct Example {
115  int* int_ptr;
116  void* void_ptr;
117  SomeClass* object_ptr;
118  const SomeClass* ptr_to_const;
119  SomeClass* const const_ptr;
120};
121```
122
123When using `raw_ptr<T>` the struct above would look as follows:
124
125```cpp
126#include "base/memory/raw_ptr.h"
127
128struct Example {
129  raw_ptr<int> int_ptr;
130  raw_ptr<void> void_ptr;
131  raw_ptr<SomeClass> object_ptr;
132  raw_ptr<const SomeClass> ptr_to_const;
133  const raw_ptr<SomeClass> const_ptr;
134};
135```
136
137In most cases, only the type in the field declaration needs to change.
138In particular, `raw_ptr<T>` implements
139`operator->`, `operator*` and other operators
140that one expects from a raw pointer.
141Cases where other code needs to be modified are described in
142[the "Recoverable compile-time problems" section](#Recoverable-compile-time-problems)
143below.
144
145## Performance
146
147### Performance impact of using |raw_ptr&lt;T&gt;| instead of |T\*|
148
149Compared to a raw C++ pointer, on platforms where USE_RAW_PTR_BACKUP_REF_IMPL
150is on, `raw_ptr<T>` incurs additional runtime
151overhead for initialization, destruction, and assignment (including
152`ptr++`, `ptr += ...`, etc.).
153There is no overhead when dereferencing or extracting a pointer (including
154`*ptr`, `ptr->foobar`, `ptr.get()`, or implicit conversions to a raw C++
155pointer).
156Finally, `raw_ptr<T>` has exactly the same memory footprint as `T*`
157(i.e. `sizeof(raw_ptr<T>) == sizeof(T*)`).
158
159One source of the performance overhead is
160a check whether a pointer `T*` points to a protected memory pool.
161This happens in `raw_ptr<T>`'s
162constructor, destructor, and assignment operators.
163If the pointed memory is unprotected,
164then `raw_ptr<T>` behaves just like a `T*`
165and the runtime overhead is limited to that extra check.
166(The security protection incurs additional overhead
167described in
168[the "Performance impact of enabling Use-after-Free protection" section](#Performance-impact-of-enabling-Use-after-Free-protection)
169below.)
170
171Some additional overhead comes from setting `raw_ptr<T>` to `nullptr`
172when default-constructed, destructed, or moved. (Yes, we said above to not rely
173on it, but to be precise this will always happen when
174USE_RAW_PTR_BACKUP_REF_IMPL is on; no guarantees otherwise.)
175
176During
177[the "Big Rewrite"](https://groups.google.com/a/chromium.org/g/chromium-dev/c/vAEeVifyf78/m/SkBUc6PhBAAJ)
178most Chromium `T*` fields have been rewritten to `raw_ptr<T>`
179(excluding fields in Renderer-only code).
180The cumulative performance impact of such rewrite
181has been measured by earlier A/B binary experiments.
182There was no measurable impact, except that 32-bit platforms
183have seen a slight increase in jankiness metrics
184(for more detailed results see
185[the document here](https://docs.google.com/document/d/1MfDT-JQh_UIpSQw3KQttjbQ_drA7zw1gQDwU3cbB6_c/edit?usp=sharing)).
186
187### Performance impact of enabling Use-after-Free protection {#Performance-impact-of-enabling-Use-after-Free-protection}
188
189When the Use-after-Free protection is enabled, then `raw_ptr<T>` has some
190additional performance overhead.
191
192The protection can increase memory usage:
193- For each memory allocation Chromium's allocator (PartitionAlloc)
194  carves out extra 4 bytes. (That doesn't necessarily mean that each allocation
195  grows by 4B. Allocation sizes come from predefined buckets, so it's possible
196  for an allocation to stay within the same bucket and incur no additional
197  overhead, or hop over to the next bucket and incur much higher overhead.)
198- Freed memory is quarantined and not available for reuse as long
199  as dangling `raw_ptr<T>` pointers exist. (In practice this overhead has been
200  observed to be low, but on a couple occasions it led to significant memory
201  leaks, fortunately caught early.)
202
203The protection increases runtime costs - `raw_ptr<T>`'s constructor,
204destructor, and assignment operators need to maintain BackupRefPtr's ref-count
205(atomic increment/decrement). `ptr++`, `ptr += ...`, etc. don't need to do that,
206but instead have to incur the cost
207of verifying that resulting pointer stays within the same allocation (important
208for BRP integrity).
209
210## When it is okay to continue using raw C++ pointers
211
212### Unsupported cases leading to compile errors {#Unsupported-cases-leading-to-compile-errors}
213
214Continue to use raw C++ pointers in the following cases, which may otherwise
215result in compile errors:
216- Function pointers
217- Pointers to Objective-C objects
218- Pointer fields in classes/structs that are used as global, static, or
219  `thread_local` variables (see more details in the
220  [Rewrite exclusion statistics](https://docs.google.com/document/d/1uAsWnwy8HfIJhDPSh1efohnqfGsv2LJmYTRBj0JzZh8/edit#heading=h.dg4eebu87wg9)
221  )
222- Pointers in unions, as well as pointer fields in classes/structs that are used
223  in unions (side note, absl::variant is strongly preferred)
224- Code that doesn’t depend on `//base` (including non-Chromium repositories and
225  third party libraries)
226- Code in `//ppapi`
227
228### Pointers to unprotected memory (performance optimization)
229
230Using `raw_ptr<T>` offers no security benefits (no UaF protection) for pointers
231that don’t point to protected memory (only PartitionAlloc-managed heap allocations
232in non-Renderer processes are protected).
233Therefore in the following cases raw C++ pointers may be used instead of
234`raw_ptr<T>`:
235- Pointer fields that can only point outside PartitionAlloc, including literals,
236  stack allocated memory, shared memory, mmap'ed memory, V8/Oilpan/Java heaps,
237  TLS, etc.
238- `const char*` (and `const wchar_t*`) pointer fields, unless you’re convinced
239  they can point to a heap-allocated object, not just a string literal
240- Pointer fields in certain renderer code. Specifically, we disallow usage in
241
242``` none
243third_party/blink/renderer/core/
244third_party/blink/renderer/platform/heap/
245third_party/blink/renderer/platform/wtf/
246```
247
248### Other perf optimizations
249
250As a performance optimization, raw C++ pointers may be used instead of
251`raw_ptr<T>` if it would have a significant
252[performance impact](#Performance).
253
254### Pointers in locations other than fields
255
256Use raw C++ pointers instead of `raw_ptr<T>` in the following scenarios:
257- Pointers in local variables and function parameters and return values. This
258  includes pointer fields in classes/structs that are used only on the stack.
259  (Using `raw_ptr<T>` here would cumulatively lead to performance regression and
260  the security benefit of UaF protection is lower for such short-lived
261  pointers.)
262- Pointer fields in unions. However, note that a much better, modern alternative
263  is `absl::variant` + `raw_ptr<T>`. If use of C++ union is absolutely
264  unavoidable, prefer a regular C++ pointer: incorrect management of a
265  `raw_ptr<T>` field can easily lead to ref-count corruption.
266- Pointers whose addresses are used only as identifiers and which are
267  never dereferenced (e.g. keys in a map). There is a performance gain
268  by not using `raw_ptr` in this case; prefer to use `uintptr_t` to
269  emphasize that the entity can dangle and must not be dereferenced. (NOTE,
270  this is a dangerous practice irrespective of raw_ptr usage, as there is a risk
271  of memory being freed and another pointer allocated with the same address!)
272
273You don’t have to, but may use `raw_ptr<T>`, in the following scenarios:
274- Pointers that are used as an element type of collections/wrappers. E.g.
275  `std::vector<T*>` and `std::vector<raw_ptr<T>>` are both okay, but prefer the
276  latter if the collection is a class field (note that some of the perf
277  optimizations above might still apply and argue for using a raw C++ pointer).
278
279### Signal Handlers
280
281`raw_ptr<T>` assumes that the allocator's data structures are in a consistent
282state. Signal handlers can interrupt in the middle of an allocation operation;
283therefore, `raw_ptr<T>` should not be used in signal handlers.
284
285## Extra pointer rules {#Extra-pointer-rules}
286
287`raw_ptr<T>` requires following some extra rules compared to a raw C++ pointer:
288- Don’t assign invalid, non-null addresses (this includes previously valid and
289  now freed memory,
290  [Win32 handles](https://crbug.com/1262017), and more). You can only assign an
291  address of memory that is valid at the time of assignment. Exceptions:
292    - a pointer to the end of a valid allocation (but not even 1 byte further)
293    - a pointer to the last page of the address space, e.g. for sentinels like
294      `reinterpret_cast<void*>(-1)`
295- Don’t initialize or assign `raw_ptr<T>` memory directly
296  (e.g. `reinterpret_cast<ClassWithRawPtr*>(buffer)` or
297  `memcpy(reinterpret_cast<void*>(&obj_with_raw_ptr), buffer)`.
298- Don’t assign to a `raw_ptr<T>` concurrently, even if the same value.
299- Don’t rely on moved-from pointers to keep their old value. Unlike raw
300  pointers, `raw_ptr<T>` may be cleared upon moving.
301- Don't use the pointer after it is destructed. Unlike raw pointers,
302  `raw_ptr<T>` may be cleared upon destruction. This may happen e.g. when fields
303  are ordered such that the pointer field is destructed before the class field
304  whose destructor uses that pointer field (e.g. see
305  [Esoteric Issues](https://docs.google.com/document/d/14Ol_adOdNpy4Ge-XReI7CXNKMzs_LL5vucDQIERDQyg/edit#heading=h.yoba1l8bnfmv)).
306- Don’t assign to a `raw_ptr<T>` until its constructor has run. This may happen
307  when a base class’s constructor uses a not-yet-initialized field of a derived
308  class (e.g. see
309  [Applying MiraclePtr](https://docs.google.com/document/d/1cnpd5Rwesq7DCZiD8FIJfPGHvQN3-Gul6xib_4hwfBg/edit?ts=5ed2d317#heading=h.4ry5d9a6fuxs)).
310
311Some of these would result in undefined behavior (UB) even in the world without
312`raw_ptr<T>` (e.g. see
313[Field destruction order](https://groups.google.com/a/chromium.org/g/memory-safety-dev/c/3sEmSnFc61I/m/ZtaeWGslAQAJ)),
314but you’d likely get away without any consequences. In the `raw_ptr<T>` world,
315an obscure crash may occur. Those crashes often manifest themselves as SEGV or
316`CHECK` inside `RawPtrBackupRefImpl::AcquireInternal()` or
317`RawPtrBackupRefImpl::ReleaseInternal()`, but you may also experience memory
318corruption or a silent drop of UaF protection.
319
320## Pointer Annotations
321
322### The AllowPtrArithmetic trait
323
324In an ideal world, a raw_ptr would point to a single object, rather than to
325a C-style array of objects accessed via pointer arithmetic, since the latter
326is best handled via a C++ construct such as base::span<> or std::vector<>.
327raw_ptrs upon which such operations are performed and for which conversion is
328desirable have been tagged with the AllowPtrArithmetic trait. That all such
329pointer are tagged can be enforced by setting the GN build arg
330enable_pointer_arithmetic_trait_check=true.
331
332### The AllowUninitialized trait
333
334When building Chromium, raw_ptrs are always nullptr initialized, either as
335the result of specific implementation that requires it (e.g. BackupRefPtr),
336or as the result of build flags (to enforce consistency). However, we provide
337an opt-out to allow third-party code to skip this step (where possible). Use
338this trait sparingly.
339
340## Recoverable compile-time problems {#Recoverable-compile-time-problems}
341
342### Explicit |raw_ptr.get()| might be needed
343
344If a raw pointer is needed, but an implicit cast from `raw_ptr<SomeClass>` to
345`SomeClass*` doesn't work, then the raw pointer needs to be obtained by explicitly
346calling `.get()`. Examples:
347- `auto* raw_ptr_var = wrapped_ptr_.get()` (`auto*` requires the initializer to
348  be a raw pointer)
349    - Alternatively you can change `auto*` to `auto&`. Avoid using `auto` as it’ll
350      copy the pointer, which incurs a performance overhead.
351- `return condition ? raw_ptr : wrapped_ptr_.get();` (ternary operator needs
352  identical types in both branches)
353- `TemplatedFunction(wrapped_ptr_.get());` (implicit cast doesn't kick in for
354  `T*` arguments in templates)
355- `printf("%p", wrapped_ptr_.get());` (can't pass class type arguments to
356  variadic functions)
357- `reinterpret_cast<SomeClass*>(wrapped_ptr_.get())` (`const_cast` and
358  `reinterpret_cast` sometimes require their argument to be a raw pointer;
359  `static_cast` should "Just Work")
360- `T2 t2 = t1_wrapped_ptr_.get();` (where there is an implicit conversion
361  constructor `T2(T1*)` the compiler can handle one implicit conversion, but not
362  two)
363- In general, when type is inferred by a compiler and then used in a context
364  where a pointer is expected.
365
366### Out-of-line constructor/destructor might be needed
367
368Out-of-line constructor/destructor may be newly required by the chromium style
369clang plugin.  Error examples:
370- `error: [chromium-style] Complex class/struct needs an explicit out-of-line
371  destructor.`
372- `error: [chromium-style] Complex class/struct needs an explicit out-of-line
373  constructor.`
374
375`raw_ptr<T>` uses a non-trivial constructor/destructor, so classes that used to
376be POD or have a trivial destructor may require an out-of-line
377constructor/destructor to satisfy the chromium style clang plugin.
378
379
380### In-out arguments need to be refactored
381
382Due to implementation difficulties,
383`raw_ptr<T>` doesn't support an address-of operator.
384This means that the following code will not compile:
385
386```cpp
387void GetSomeClassPtr(SomeClass** out_arg) {
388  *out_arg = ...;
389}
390
391struct MyStruct {
392  void Example() {
393    GetSomeClassPtr(&wrapped_ptr_);  // <- won't compile
394  }
395
396  raw_ptr<SomeClass> wrapped_ptr_;
397};
398```
399
400The typical fix is to change the type of the out argument
401(see also [an example CL here](https://crrev.com/c/4545743)):
402
403```cpp
404void GetSomeClassPtr(raw_ptr<SomeClass>* out_arg) {
405  *out_arg = ...;
406}
407```
408
409Similarly this code:
410
411```cpp
412void FillPtr(SomeClass*& out_arg) {
413  out_arg = ...;
414}
415```
416
417would have to be changed to this:
418
419```cpp
420void FillPtr(raw_ptr<SomeClass>& out_arg) {
421  out_arg = ...;
422}
423```
424
425Similarly this code:
426
427```cpp
428SomeClass*& GetPtr() {
429  return wrapper_ptr_;
430}
431```
432
433would have to be changed to this:
434
435```cpp
436raw_ptr<SomeClass>& GetPtr() {
437  return wrapper_ptr_;
438}
439```
440
441
442In case you cannot refactor the in-out arguments (e.g. third party library), you
443may use `raw_ptr.AsEphemeralRawAddr()` to obtain *extremely* short-lived
444`T**` or `T*&`. You should not treat `T**` obtained via
445`raw_ptr.AsEphemeralRawAddr()` as a normal pointer pointer, and must follow
446these requirements.
447
448- Do NOT store `T**` or `T*&` anywhere, even as a local variable.
449  - It will become invalid very quickly and can cause dangling pointer issue
450- Do NOT use `raw_ptr<T>`, `T**` or `T*&` multiple times within an expression.
451  - The implementation assumes raw_ptr<T> is never accessed when `T**` or `T*&`
452    is alive.
453
454```cpp
455void GetSomeClassPtr(SomeClass** out_arg) {
456  *out_arg = ...;
457}
458void FillPtr(SomeClass*& out_arg) {
459  out_arg = ...;
460}
461void Foo() {
462  raw_ptr<SomeClass> ptr;
463  GetSomeClassPtr(&ptr.AsEphemeralRawAddr());
464  FillPtr(ptr.AsEphemeralRawAddr()); // Implicitly converted into |SomeClass*&|.
465}
466```
467
468Technically, `raw_ptr.AsEphemeralRawAddr()` generates a temporary instance of
469`raw_ptr<T>::EphemeralRawAddr`, which holds a temporary copy of `T*`.
470`T**` and `T*&` points to a copied version of the original pointer and
471any modification made via `T**` or `T*&` is written back on destruction of
472`EphemeralRawAddr` instance.
473C++ guarantees a temporary object returned by `raw_ptr.AsEphemeralRawAddr()`
474lives until completion of evaluation of "full-expression" (i.e. the outermost
475expression). This makes it possible to use `T**` and `T*&` within single
476expression like in-out param.
477
478```cpp
479struct EphemeralRawAddr {
480  EphemeralRawAddr(raw_ptr& ptr): copy(ptr.get()), original(ptr) {}
481  ~EphemeralRawAddr() {
482    original = copy;
483    copy = nullptr;
484  }
485
486  T** operator&() { return &copy; }
487  operator T*&() { return copy; }
488
489  T* copy;
490  raw_ptr& original;  // Original pointer.
491};
492```
493
494
495### Modern |nullptr| is required
496
497As recommended by the Google C++ Style Guide,
498[use nullptr instead of NULL](https://google.github.io/styleguide/cppguide.html#0_and_nullptr/NULL) -
499the latter might result in compile-time errors when used with `raw_ptr<T>`.
500
501Example:
502
503```cpp
504struct SomeStruct {
505  raw_ptr<int> ptr_field;
506};
507
508void bar() {
509  SomeStruct some_struct;
510  some_struct.ptr_field = NULL;
511}
512```
513
514Error:
515```err
516../../base/memory/checked_ptr_unittest.cc:139:25: error: use of overloaded
517operator '=' is ambiguous (with operand types raw_ptr<int>' and 'long')
518  some_struct.ptr_field = NULL;
519  ~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~
520../../base/memory/raw_ptr.h:369:29: note: candidate function
521  ALWAYS_INLINE raw_ptr& operator=(std::nullptr_t) noexcept {
522                         ^
523../../base/memory/raw_ptr.h:374:29: note: candidate function
524  ALWAYS_INLINE raw_ptr& operator=(T* p)
525                         noexcept {
526```
527
528### [rare] Explicit overload or template specialization for |raw_ptr&lt;T&gt;|
529
530In rare cases, the default template code won’t compile when `raw_ptr<...>` is
531substituted for a template argument.  In such cases, it might be necessary to
532provide an explicit overload or template specialization for `raw_ptr<T>`.
533
534Example (more details in
535[Applying MiraclePtr](https://docs.google.com/document/d/1cnpd5Rwesq7DCZiD8FIJfPGHvQN3-Gul6xib_4hwfBg/edit?ts=5ed2d317#heading=h.o2pf3fg0zzf) and the
536[Add CheckedPtr support for cbor_extract::Element](https://chromium-review.googlesource.com/c/chromium/src/+/2224954)
537CL):
538
539```cpp
540// An explicit overload (taking raw_ptr<T> as an argument)
541// was needed below:
542template <typename S>
543constexpr StepOrByte<S> Element(
544    const Is required,
545    raw_ptr<const std::string> S::*member,  // <- HERE
546    uintptr_t offset) {
547  return ElementImpl<S>(required, offset, internal::Type::kString);
548}
549```
550
551## AddressSanitizer support
552
553For years, AddressSanitizer has been the main tool for diagnosing memory
554corruption issues in Chromium. MiraclePtr alters the security properties of some
555of some such issues, so ideally it should be integrated with ASan. That way an
556engineer would be able to check whether a given use-after-free vulnerability is
557covered by the protection without having to switch between ASan and non-ASan
558builds.
559
560Unfortunately, MiraclePtr relies heavily on PartitionAlloc, and ASan needs its
561own allocator to work. As a result, the default implementation of `raw_ptr<T>`
562can't be used with ASan builds. Instead, a special version of `raw_ptr<T>` has
563been implemented, which is based on the ASan quarantine and acts as a
564sufficiently close approximation for diagnostic purposes. At crash time, the
565tool will tell the user if the dangling pointer access would have been protected
566by MiraclePtr *in a regular build*.
567
568You can configure the diagnostic tool by modifying the parameters of the feature
569flag `PartitionAllocBackupRefPtr`. For example, launching Chromium as follows:
570
571```
572path/to/chrome --enable-features=PartitionAllocBackupRefPtr:enabled-processes/browser-only/asan-enable-dereference-check/true/asan-enable-extraction-check/true/asan-enable-instantiation-check/true
573```
574
575activates all available checks in the browser process.
576
577### Available checks
578
579MiraclePtr provides ASan users with three kinds of security checks, which differ
580in when a particular check occurs:
581
582#### Dereference
583
584This is the basic check type that helps diagnose regular heap-use-after-free
585bugs. It's enabled by default.
586
587#### Extraction
588
589The user will be warned if a dangling pointer is extracted from a `raw_ptr<T>`
590variable. If the pointer is then dereferenced, an ASan error report will follow.
591In some cases, extra work on the reproduction case is required to reach the
592faulty memory access. However, even without memory corruption, relying on the
593value of a dangling pointer may lead to problems. For example, it's a common
594(anti-)pattern in Chromium to use a raw pointer as a key in a container.
595Consider the following example:
596
597```
598std::map<T*, std::unique_ptr<Ext>> g_map;
599
600struct A {
601  A() {
602    g_map[this] = std::make_unique<Ext>(this);
603  }
604
605  ~A() {
606    g_map.erase(this);
607  }
608};
609
610raw_ptr<A> dangling = new A;
611// ...
612delete dangling.get();
613A* replacement = new A;
614// ...
615auto it = g_map.find(dangling);
616if (it == g_map.end())
617  return 0;
618it->second.DoStuff();
619```
620
621Depending on whether the allocator reuses the same memory region for the second
622`A` object, the program may inadvertently call `DoStuff()` on the wrong `Ext`
623instance. This, in turn, may corrupt the state of the program or bypass security
624controls if the two `A` objects belong to different security contexts.
625
626Given the proportion of false positives reported in the mode, it is disabled by
627default. It's mainly intended to be used by security researchers who are willing
628to spend a significant amount of time investigating these early warnings.
629
630#### Instantiation
631
632This check detects violations of the rule that when instantiating a `raw_ptr<T>`
633from a `T*` , it is only allowed if the `T*` is a valid (i.e. not dangling)
634pointer. This rule exists to help avoid an issue called "pointer laundering"
635which can result in unsafe `raw_ptr<T>` instances that point to memory that is
636no longer in quarantine. This is important, since subsequent use of these
637`raw_ptr<T>` might appear to be safe.
638
639In order for "pointer laundering" to occur, we need (1) a dangling `T*`
640(pointing to memory that has been freed) to be assigned to a `raw_ptr<T>`, while
641(2) there is no other `raw_ptr<T>` pointing to the same object/allocation at the
642time of assignment.
643
644The check only detects (1), a dangling `T*` being assigned to a `raw_ptr<T>`, so
645in order to determine whether "pointer laundering" has occurred, we need to
646determine whether (2) could plausibly occur, not just in the specific
647reproduction testcase, but in the more general case.
648
649In the absence of thorough reasoning about (2), the assumption here should be
650that any failure of this check is a security issue of the same severity as an
651unprotected use-after-free.
652
653### Protection status
654
655When ASan generates a heap-use-after-free report, it will include a new section
656near the bottom, which starts with the line `MiraclePtr Status: <status>`. At
657the moment, it has three possible options:
658
659#### Protected
660
661The system is sufficiently confident that MiraclePtr makes the discovered issue
662unexploitable. In the future, the security severity of such bugs will be
663reduced.
664
665#### Manual analysis required
666
667Dangling pointer extraction was detected before the crash, but there might be
668extra code between the extraction and dereference. Most of the time, the code in
669question will look similar to the following:
670
671```
672struct A {
673  raw_ptr<T> dangling_;
674};
675
676void trigger(A* a) {
677  // ...
678  T* local = a->dangling_;
679  DoStuff();
680  local->DoOtherStuff();
681  // ...
682}
683```
684
685In this scenario, even though `dangling_` points to freed memory, that memory
686is protected and will stay in quarantine until `dangling_` (and all other
687`raw_ptr<T>` variables pointing to the same region) changes its value or gets
688destroyed. Therefore, the expression `a_->dangling->DoOtherStuff()` wouldn't
689trigger an exploitable use-after-free.
690
691You will need to make sure that `DoStuff()` is sufficiently trivial and can't
692(not only for the particular reproduction case, but *even in principle*) make
693`dangling_` change its value or get destroyed. If that's the case, the
694`DoOtherStuff()` call may be considered protected. The tool will provide you
695with the stack trace for both the extraction and dereference events.
696
697#### Not protected
698
699The dangling `T*` doesn't appear to originate from a `raw_ptr<T>` variable,
700which means MiraclePtr can't prevent this issue from being exploited. In
701practice, there may still be a `raw_ptr<T>` in a different part of the code that
702protects the same allocation indirectly, but such protection won't be considered
703robust enough to impact security-related decisions.
704
705### Limitations
706
707The main limitation of MiraclePtr in ASan builds is the main limitation of ASan
708itself: the capacity of the quarantine is limited. Eventually, every allocation
709in quarantine will get reused regardless of whether there are still references
710to it.
711
712In the context of MiraclePtr combined with ASan, it's a problem when:
713
7141. A heap allocation that isn't supported by MiraclePtr is made. At the moment,
715   the only such class is allocations made early during the process startup
716   before MiraclePtr can be activated.
7172. Its address is assigned to a `raw_ptr<T>` variable.
7183. The allocation gets freed.
7194. A new allocation is made in the same memory region as the first one, but this
720   time it is supported.
7215. The second allocation gets freed.
7226. The `raw_ptr<T>` variable is accessed.
723
724In this case, MiraclePtr will incorrectly assume the memory access is protected.
725Luckily, considering the small number of unprotected allocations in Chromium,
726the size of the quarantine, and the fact that most reproduction cases take
727relatively short time to run, the odds of this happening are very low.
728
729The problem is relatively easy to spot if you look at the ASan report: the
730allocation and deallocation stack traces won't be consistent across runs and
731the allocation type won't match the use stack trace.
732
733If you encounter a suspicious ASan report, it may be helpful to re-run Chromium
734with an increased quarantine capacity as follows:
735
736```
737ASAN_OPTIONS=quarantine_size_mb=1024 path/to/chrome
738```
739
740## Appendix: Is raw_ptr Live?
741
742![Diagram showing how both code support and feature flag must be present
743  for raw_ptr to be BRP.](./raw_ptr_liveness.png)
744
745Note that
746
747*   [`RawPtrNoOpImpl`][raw-ptr-noop-impl] is thought to have no
748    overhead. However, this has yet to be verified.
749
750*   "Inert BackupRefPtr" _has_ overhead - once BRP support is compiled
751    in, every `raw_ptr` will (at assignment) perform the
752    check that asks, ["is BRP protection active?"][is-brp-active]
753
754As for general BRP enablement,
755
756*   BRP is live in most browser tests and Chromium targets.
757
758    *   This is nuanced by platform type and process type.
759
760*   In unit tests,
761
762    *   `raw_ptr` is the no-op impl when the build is ASan.
763
764    *   `raw_ptr` is live BRP on bots.
765
766    *   `raw_ptr` is inert BRP otherwise (see https://crbug.com/1440658).
767
768[raw-ptr-noop-impl]: https://source.chromium.org/search?q=class:RawPtrNoOpImpl&ss=chromium
769[is-brp-active]: https://source.chromium.org/search?q=func:RawPtrBackupRefImpl::IsSupportedAndNotNull&ss=chromium
770