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