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