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<T>| 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<T>| 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<T>| 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<T>| 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 © } 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<T>| 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 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