# raw_ptr&lt;T&gt; (aka MiraclePtr, aka BackupRefPtr)

`raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety over
raw pointers.  It behaves just like a raw pointer on platforms where
USE_BACKUP_REF_PTR is off, and almost like one when it's on. The main
difference is that when USE_BACKUP_REF_PTR is enabled, it's zero-initialized and
cleared on destruction and move. (You should continue to explicitly initialize
raw_ptr members to ensure consistent behavior on platforms where USE_BACKUP_REF_PTR
is disabled.) Unlike `std::unique_ptr<T>`, `base::scoped_refptr<T>`, etc., it
doesn’t manage ownership or lifetime of an allocated object - you are still
responsible for freeing the object when no longer used, just as you would
with a raw C++ pointer.

`raw_ptr<T>` is beneficial for security, because it can prevent a significant
percentage of Use-after-Free
(UaF) bugs from being exploitable (by poisoning the freed memory and
quarantining it as long as a dangling `raw_ptr<T>` exists).
`raw_ptr<T>` has limited impact on stability - dereferencing
a dangling pointer remains Undefined Behavior (although poisoning may
lead to earlier, easier to debug crashes).
Note that the security protection is not yet enabled by default.

`raw_ptr<T>` is a part of
[the MiraclePtr project](https://docs.google.com/document/d/1pnnOAIz_DMWDI4oIOFoMAqLnf_MZ2GsrJNb_dbQ3ZBg/edit?usp=sharing)
and currently implements
[the BackupRefPtr algorithm](https://docs.google.com/document/d/1m0c63vXXLyGtIGBi9v6YFANum7-IRC3-dmiYBCWqkMk/edit?usp=sharing).
If needed, please reach out to
[memory-safety-dev@chromium.org](https://groups.google.com/u/1/a/chromium.org/g/memory-safety-dev)
or (Google-internal)
[chrome-memory-safety@google.com](https://groups.google.com/a/google.com/g/chrome-memory-safety)
with questions or concerns.

[TOC]

## When to use |raw_ptr&lt;T&gt;|

[The Chromium C++ Style Guide](../../styleguide/c++/c++.md#non_owning-pointers-in-class-fields)
asks to use `raw_ptr<T>` for class and struct fields in place of
a raw C++ pointer `T*` whenever possible, except in Renderer-only code.
This guide offers more details.

The usage guidelines are *not* enforced currently (the MiraclePtr team will turn
on enforcement via Chromium Clang Plugin after confirming performance results
via Stable channel experiments).  Afterwards we plan to allow
exclusions via:
- [manual-paths-to-ignore.txt](../../tools/clang/rewrite_raw_ptr_fields/manual-paths-to-ignore.txt)
  to exclude at a directory level.  Examples:
    - Renderer-only code (i.e. code in paths that contain `/renderer/` or
      `third_party/blink/public/web/`)
    - Code that cannot depend on `//base`
    - Code in `//ppapi`
- `RAW_PTR_EXCLUSION` C++ attribute to exclude individual fields.  Examples:
    - Cases where `raw_ptr<T>` won't compile (e.g. cases covered in
      [the "Unsupported cases leading to compile errors" section](#Unsupported-cases-leading-to-compile-errors)).
      Make sure to also look at
      [the "Recoverable compile-time problems" section](#Recoverable-compile_time-problems).
    - Cases where the pointer always points outside of PartitionAlloc
      (e.g.  literals, stack allocated memory, shared memory, mmap'ed memory,
      V8/Oilpan/Java heaps, TLS, etc.).
    - (Very rare) cases that cause regression on perf bots.
    - (Very rare) cases where `raw_ptr<T>` can lead to runtime errors.
      Make sure to look at
      [the "Extra pointer rules" section](#Extra-pointer-rules)
      before resorting to this exclusion.
- No explicit exclusions will be needed for:
    - `const char*`, `const wchar_t*`, etc.
    - Function pointers
    - ObjC pointers

## Examples of using |raw_ptr&lt;T&gt;| instead of raw C++ pointers

Consider an example struct that uses raw C++ pointer fields:

```cpp
struct Example {
  int* int_ptr;
  void* void_ptr;
  SomeClass* object_ptr;
  const SomeClass* ptr_to_const;
  SomeClass* const const_ptr;
};
```

When using `raw_ptr<T>` the struct above would look as follows:

```cpp
#include "base/memory/raw_ptr.h"

struct Example {
  raw_ptr<int> int_ptr;
  raw_ptr<void> void_ptr;
  raw_ptr<SomeClass> object_ptr;
  raw_ptr<const SomeClass> ptr_to_const;
  const raw_ptr<SomeClass> const_ptr;
};
```

In most cases, only the type in the field declaration needs to change.
In particular, `raw_ptr<T>` implements
`operator->`, `operator*` and other operators
that one expects from a raw pointer.
Cases where other code needs to be modified are described in
[the "Recoverable compile-time problems" section](#Recoverable-compile_time-problems)
below.

## Performance

### Performance impact of using |raw_ptr&lt;T&gt;| instead of |T\*|

Compared to a raw C++ pointer, on platforms where USE_BACKUP_REF_PTR is on,
`raw_ptr<T>` incurs additional runtime
overhead for initialization, destruction, and assignment (including
`ptr++` and `ptr += ...`).
There is no overhead when dereferencing or extracting a pointer (including
`*ptr`, `ptr->foobar`, `ptr.get()`, or implicit conversions to a raw C++
pointer).
Finally, `raw_ptr<T>` has exactly the same memory footprint as `T*`
(i.e. `sizeof(raw_ptr<T>) == sizeof(T*)`).

One source of the performance overhead is
a check whether a pointer `T*` points to a protected memory pool.
This happens in `raw_ptr<T>`'s
constructor, destructor, and assignment operators.
If the pointed memory is unprotected,
then `raw_ptr<T>` behaves just like a `T*`
and the runtime overhead is limited to the extra check.
(The security protection incurs additional overhead
described in
[the "Performance impact of enabling Use-after-Free protection" section](#Performance-impact-of-enabling-Use_after_Free-protection)
below.)

Some additional overhead comes from setting `raw_ptr<T>` to `nullptr`
when default-constructed, destructed, or moved.

During
[the "Big Rewrite"](https://groups.google.com/a/chromium.org/g/chromium-dev/c/vAEeVifyf78/m/SkBUc6PhBAAJ)
most Chromium `T*` fields have been rewritten to `raw_ptr<T>`
(excluding fields in Renderer-only code).
The cumulative performance impact of such rewrite
has been measured by earlier A/B binary experiments.
There was no measurable impact, except that 32-bit platforms
have seen a slight increase in jankiness metrics
(for more detailed results see
[the document here](https://docs.google.com/document/d/1MfDT-JQh_UIpSQw3KQttjbQ_drA7zw1gQDwU3cbB6_c/edit?usp=sharing)).

### Performance impact of enabling Use-after-Free protection

When the Use-after-Free protection is enabled, then `raw_ptr<T>` has some
additional performance overhead.  This protection is currently disabled
by default.  We will enable the protection incrementally, starting with
more non-Renderer processes first.

The protection can increase memory usage:
- For each memory allocation Chromium's allocator (PartitionAlloc)
  allocates extra 16 bytes (4 bytes to store the BackupRefPtr's
  ref-count associated with the allocation, the rest to maintain
  alignment requirements).
- Freed memory is quarantined and not available for reuse as long
  as dangling `raw_ptr<T>` pointers exist.
- Enabling protection requires additional partitions in PartitionAlloc,
  which increases memory fragmentation.

The protection can increase runtime costs - `raw_ptr<T>`'s constructor,
destructor, and assignment operators (including `ptr++` and `ptr += ...`) need
to maintain BackupRefPtr's ref-count.

## When it is okay to continue using raw C++ pointers

### Unsupported cases leading to compile errors

Using raw_ptr<T> in the following scenarios will lead to build errors.
Continue to use raw C++ pointers in those cases:
- Function pointers
- Pointers to Objective-C objects
- Pointer fields in classes/structs that are used as global or static variables
  (see more details in the
  [Rewrite exclusion statistics](https://docs.google.com/document/d/1uAsWnwy8HfIJhDPSh1efohnqfGsv2LJmYTRBj0JzZh8/edit#heading=h.dg4eebu87wg9)
  )
- Pointer fields that require non-null, constexpr initialization
  (see more details in the
  [Rewrite exclusion statistics](https://docs.google.com/document/d/1uAsWnwy8HfIJhDPSh1efohnqfGsv2LJmYTRBj0JzZh8/edit#heading=h.dg4eebu87wg9)
  )
- Pointer fields in classes/structs that have to be trivially constructible or
  destructible
- Code that doesn’t depend on `//base` (including non-Chromium repositories and
  third party libraries)
- Code in `//ppapi`

### Pointers to unprotected memory (performance optimization)

Using `raw_ptr<T>` offers no security benefits (no UaF protection) for pointers
that don’t point to protected memory (only PartitionAlloc-managed heap allocations
in non-Renderer processes are protected).
Therefore in the following cases raw C++ pointers may be used instead of
`raw_ptr<T>`:
- Pointer fields that can only point outside PartitionAlloc, including literals,
  stack allocated memory, shared memory, mmap'ed memory, V8/Oilpan/Java heaps,
  TLS, etc.
- `const char*` (and `const wchar_t*`) pointer fields, unless you’re convinced
  they can point to a heap-allocated object, not just a string literal
- Pointer fields that can only point to aligned allocations (requested via
  PartitionAlloc’s `AlignedAlloc` or `memalign` family of functions, with
  alignment higher than `base::kAlignment`)
- Pointer fields in Renderer-only code.  (This might change in the future
  as we explore expanding `raw_ptr<T>` usage in https://crbug.com/1273204.)

### Other perf optimizations

As a performance optimization, raw C++ pointers may be used instead of
`raw_ptr<T>` if it would have a significant
[performance impact](#Performance).

### Pointers in locations other than fields

Use raw C++ pointers instead of `raw_ptr<T>` in the following scenarios:
- Pointers in local variables and function/method parameters.
  This includes pointer fields in classes/structs that are used only on the stack.
  (We plan to enforce this in the Chromium Clang Plugin.  Using `raw_ptr<T>`
  here would cumulatively lead to performance regression and the security
  benefit of UaF protection is lower for such short-lived pointers.)
- Pointer fields in unions. (Naive usage this will lead to
  [a C++ compile
  error](https://docs.google.com/document/d/1uAsWnwy8HfIJhDPSh1efohnqfGsv2LJmYTRBj0JzZh8/edit#heading=h.fvvnv6htvlg3).
  Avoiding the error requires the `raw_ptr<T>` destructor to be explicitly
  called before destroying the union, if the field is holding a value. Doing
  this manual destruction wrong might lead to leaks or double-dereferences.)
- Pointers whose addresses are used only as identifiers and which are
  never dereferenced (e.g. keys in a map). There is a performance gain
  by not using `raw_ptr` in this case; prefer to use `uintptr_t` to
  emphasize that the entity can dangle and must not be dereferenced.

You don’t have to, but may use `raw_ptr<T>`, in the following scenarios:
- Pointers that are used as an element type of collections/wrappers. E.g.
  `std::vector<T*>` and `std::vector<raw_ptr<T>>` are both okay, but prefer the
  latter if the collection is a class field (note that some of the perf
  optimizations above might still apply and argue for using a raw C++ pointer).


## Extra pointer rules

`raw_ptr<T>` requires following some extra rules compared to a raw C++ pointer:
- Don’t assign invalid, non-null addresses (this includes previously valid and
  now freed memory,
  [Win32 handles](https://crbug.com/1262017), and more). You can only assign an
  address of memory that is allocated at the time of assignment. Exceptions:
    - a pointer to the end of a valid allocation (but not even 1 byte further)
    - a pointer to the last page of the address space, e.g. for sentinels like
      `reinterpret_cast<void*>(-1)`
- Don’t initialize or assign `raw_ptr<T>` memory directly
  (e.g. `reinterpret_cast<ClassWithRawPtr*>(buffer)` or
  `memcpy(reinterpret_cast<void*>(&obj_with_raw_ptr), buffer)`.
- Don’t assign to a `raw_ptr<T>` concurrently, even if the same value.
- Don’t rely on moved-from pointers to keep their old value. Unlike raw
  pointers, `raw_ptr<T>` is cleared upon moving.
- Don't use the pointer after it is destructed. Unlike raw pointers,
  `raw_ptr<T>` is cleared upon destruction. This may happen e.g. when fields are
  ordered such that the pointer field is destructed before the class field whose
  destructor uses that pointer field (e.g. see
  [Esoteric Issues](https://docs.google.com/document/d/14Ol_adOdNpy4Ge-XReI7CXNKMzs_LL5vucDQIERDQyg/edit#heading=h.yoba1l8bnfmv)).
- Don’t assign to a `raw_ptr<T>` until its constructor has run. This may happen
  when a base class’s constructor uses a not-yet-initialized field of a derived
  class (e.g. see
  [Applying MiraclePtr](https://docs.google.com/document/d/1cnpd5Rwesq7DCZiD8FIJfPGHvQN3-Gul6xib_4hwfBg/edit?ts=5ed2d317#heading=h.4ry5d9a6fuxs)).

Some of these would result in undefined behavior (UB) even in the world without
`raw_ptr<T>` (e.g. see
[Field destruction order](https://groups.google.com/a/chromium.org/g/memory-safety-dev/c/3sEmSnFc61I/m/ZtaeWGslAQAJ)),
but you’d likely get away without any consequences. In the `raw_ptr<T>` world,
an obscure crash may occur. Those crashes often manifest themselves as SEGV or
`CHECK` inside `BackupRefPtrImpl::AcquireInternal()` or
`BackupRefPtrImpl::ReleaseInternal()`, but you may also experience memory
corruption or a silent drop of UaF protection.

## Recoverable compile-time problems

### Explicit |raw_ptr.get()| might be needed

If a raw pointer is needed, but an implicit cast from `raw_ptr<SomeClass>` to
`SomeClass*` doesn't work, then the raw pointer needs to be obtained by explicitly
calling `.get()`. Examples:
- `auto* raw_ptr_var = wrapped_ptr_.get()` (`auto*` requires the initializer to
  be a raw pointer)
    - Alternatively you can change `auto*` to `auto&`. Avoid using `auto` as it’ll
      copy the pointer, which incurs a performance overhead.
- `return condition ? raw_ptr : wrapped_ptr_.get();` (ternary operator needs
  identical types in both branches)
- `base::WrapUniquePtr(wrapped_ptr_.get());` (implicit cast doesn't kick in for
  arguments in templates)
- `printf("%p", wrapped_ptr_.get());` (can't pass class type arguments to
  variadic functions)
- `reinterpret_cast<SomeClass*>(wrapped_ptr_.get())` (`const_cast` and
  `reinterpret_cast` sometimes require their argument to be a raw pointer;
  `static_cast` should "Just Work")
- `T2 t2 = t1_wrapped_ptr_.get();` (where there is an implicit conversion
  constructor `T2(T1*)` the compiler can handle one implicit conversion, but not
  two)
- In general, when type is inferred by a compiler and then used in a context
  where a pointer is expected.

### Out-of-line constructor/destructor might be needed

Out-of-line constructor/destructor may be newly required by the chromium style
clang plugin.  Error examples:
- `error: [chromium-style] Complex class/struct needs an explicit out-of-line
  destructor.`
- `error: [chromium-style] Complex class/struct needs an explicit out-of-line
  constructor.`

`raw_ptr<T>` uses a non-trivial constructor/destructor, so classes that used to
be POD or have a trivial destructor may require an out-of-line
constructor/destructor to satisfy the chromium style clang plugin.


### In-out arguments need to be refactored

Due to implementation difficulties,
`raw_ptr<T>` doesn't support an address-of operator.
This means that the following code will not compile:

```cpp
void GetSomeClassPtr(SomeClass** out_arg) {
  *out_arg = ...;
}

struct MyStruct {
  void Example() {
    GetSomeClassPtr(&wrapped_ptr_);  // <- won't compile
  }

  raw_ptr<SomeClass> wrapped_ptr_;
};
```

The typical fix is to change the type of the out argument:

```cpp
void GetSomeClassPtr(raw_ptr<SomeClass>* out_arg) {
  *out_arg = ...;
}
```

Similarly this code:

```cpp
void FillPtr(SomeClass*& out_arg) {
  out_arg = ...;
}
```

would have to be changed to this:

```cpp
void FillPtr(raw_ptr<SomeClass>& out_arg) {
  out_arg = ...;
}
```

Similarly this code:

```cpp
SomeClass*& GetPtr() {
  return wrapper_ptr_;
}
```

would have to be changed to this:

```cpp
raw_ptr<SomeClass>& GetPtr() {
  return wrapper_ptr_;
}
```

### Modern |nullptr| is required

As recommended by the Google C++ Style Guide,
[use nullptr instead of NULL](https://google.github.io/styleguide/cppguide.html#0_and_nullptr/NULL) -
the latter might result in compile-time errors when used with `raw_ptr<T>`.

Example:

```cpp
struct SomeStruct {
  raw_ptr<int> ptr_field;
};

void bar() {
  SomeStruct some_struct;
  some_struct.ptr_field = NULL;
}
```

Error:
```err
../../base/memory/checked_ptr_unittest.cc:139:25: error: use of overloaded
operator '=' is ambiguous (with operand types raw_ptr<int>' and 'long')
  some_struct.ptr_field = NULL;
  ~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~
../../base/memory/raw_ptr.h:369:29: note: candidate function
  ALWAYS_INLINE raw_ptr& operator=(std::nullptr_t) noexcept {
                         ^
../../base/memory/raw_ptr.h:374:29: note: candidate function
  ALWAYS_INLINE raw_ptr& operator=(T* p)
                         noexcept {
```

### [rare] Explicit overload or template specialization for |raw_ptr&lt;T&gt;|

In rare cases, the default template code won’t compile when `raw_ptr<...>` is
substituted for a template argument.  In such cases, it might be necessary to
provide an explicit overload or template specialization for `raw_ptr<T>`.

Example (more details in
[Applying MiraclePtr](https://docs.google.com/document/d/1cnpd5Rwesq7DCZiD8FIJfPGHvQN3-Gul6xib_4hwfBg/edit?ts=5ed2d317#heading=h.o2pf3fg0zzf) and the
[Add CheckedPtr support for cbor_extract::Element](https://chromium-review.googlesource.com/c/chromium/src/+/2224954)
CL):

```cpp
// An explicit overload (taking raw_ptr<T> as an argument)
// was needed below:
template <typename S>
constexpr StepOrByte<S> Element(
    const Is required,
    raw_ptr<const std::string> S::*member,  // <- HERE
    uintptr_t offset) {
  return ElementImpl<S>(required, offset, internal::Type::kString);
}
```

## AddressSanitizer support

For years, AddressSanitizer has been the main tool for diagnosing memory
corruption issues in Chromium. MiraclePtr alters the security properties of some
of some such issues, so ideally it should be integrated with ASan. That way an
engineer would be able to check whether a given use-after-free vulnerability is
covered by the protection without having to switch between ASan and non-ASan
builds.

Unfortunately, MiraclePtr relies heavily on PartitionAlloc, and ASan needs its
own allocator to work. As a result, the default implementation of `raw_ptr<T>`
can't be used with ASan builds. Instead, a special version of `raw_ptr<T>` has
been implemented, which is based on the ASan quarantine and acts as a
sufficiently close approximation for diagnostic purposes. At crash time, the
tool will tell the user if the dangling pointer access would have been protected
by MiraclePtr *in a regular build*.

You can configure the diagnostic tool by modifying the parameters of the feature
flag `PartitionAllocBackupRefPtr`. For example, launching Chromium as follows:

```
path/to/chrome --enable-features=PartitionAllocBackupRefPtr:enabled-processes/browser-only/asan-enable-dereference-check/true/asan-enable-extraction-check/true/asan-enable-instantiation-check/true
```

activates all available checks in the browser process.

### Available checks

MiraclePtr provides ASan users with three kinds of security checks, which differ
in when a particular check occurs:

#### Dereference

This is the basic check type that helps diagnose regular heap-use-after-free
bugs. It's enabled by default.

#### Extraction

The user will be warned if a dangling pointer is extracted from a `raw_ptr<T>`
variable. If the pointer is then dereferenced, an ASan error report will follow.
In some cases, extra work on the reproduction case is required to reach the
faulty memory access. However, even without memory corruption, relying on the
value of a dangling pointer may lead to problems. For example, it's a common
(anti-)pattern in Chromium to use a raw pointer as a key in a container.
Consider the following example:

```
std::map<T*, std::unique_ptr<Ext>> g_map;

struct A {
  A() {
    g_map[this] = std::make_unique<Ext>(this);
  }

  ~A() {
    g_map.erase(this);
  }
};

raw_ptr<A> dangling = new A;
// ...
delete dangling.get();
A* replacement = new A;
// ...
auto it = g_map.find(dangling);
if (it == g_map.end())
  return 0;
it->second.DoStuff();
```

Depending on whether the allocator reuses the same memory region for the second
`A` object, the program may inadvertently call `DoStuff()` on the wrong `Ext`
instance. This, in turn, may corrupt the state of the program or bypass security
controls if the two `A` objects belong to different security contexts.

Given the proportion of false positives reported in the mode, it is disabled by
default. It's mainly intended to be used by security researchers who are willing
to spend a significant amount of time investigating these early warnings.

#### Instantiation

This check detects violations of the rule that when instantiating a `raw_ptr<T>`
from a `T*` , it is only allowed if the `T*` is a valid (i.e. not dangling)
pointer. This rule exists to help avoid an issue called "pointer laundering"
which can result in unsafe `raw_ptr<T>` instances that point to memory that is
no longer in quarantine. This is important, since subsequent use of these
`raw_ptr<T>` might appear to be safe.

In order for "pointer laundering" to occur, we need (1) a dangling `T*`
(pointing to memory that has been freed) to be assigned to a `raw_ptr<T>`, while
(2) there is no other `raw_ptr<T>` pointing to the same object/allocation at the
time of assignment.

The check only detects (1), a dangling `T*` being assigned to a `raw_ptr<T>`, so
in order to determine whether "pointer laundering" has occurred, we need to
determine whether (2) could plausibly occur, not just in the specific
reproduction testcase, but in the more general case.

In the absence of thorough reasoning about (2), the assumption here should be
that any failure of this check is a security issue of the same severity as an
unprotected use-after-free.

### Protection status

When ASan generates a heap-use-after-free report, it will include a new section
near the bottom, which starts with the line `MiraclePtr Status: <status>`. At
the moment, it has three possible options:

#### Protected

The system is sufficiently confident that MiraclePtr makes the discovered issue
unexploitable. In the future, the security severity of such bugs will be
reduced.

#### Manual analysis required

Dangling pointer extraction was detected before the crash, but there might be
extra code between the extraction and dereference. Most of the time, the code in
question will look similar to the following:

```
struct A {
  raw_ptr<T> dangling_;
};

void trigger(A* a) {
  // ...
  T* local = a->dangling_;
  DoStuff();
  local->DoOtherStuff();
  // ...
}
```

In this scenario, even though `dangling_` points to freed memory, that memory
is protected and will stay in quarantine until `dangling_` (and all other
`raw_ptr<T>` variables pointing to the same region) changes its value or gets
destroyed. Therefore, the expression `a_->dangling->DoOtherStuff()` wouldn't
trigger an exploitable use-after-free.

You will need to make sure that `DoStuff()` is sufficiently trivial and can't
(not only for the particular reproduction case, but *even in principle*) make
`dangling_` change its value or get destroyed. If that's the case, the
`DoOtherStuff()` call may be considered protected. The tool will provide you
with the stack trace for both the extraction and dereference events.

#### Not protected

The dangling `T*` doesn't appear to originate from a `raw_ptr<T>` variable,
which means MiraclePtr can't prevent this issue from being exploited. In
practice, there may still be a `raw_ptr<T>` in a different part of the code that
protects the same allocation indirectly, but such protection won't be considered
robust enough to impact security-related decisions.

### Limitations

The main limitation of MiraclePtr in ASan builds is the main limitation of ASan
itself: the capacity of the quarantine is limited. Eventually, every allocation
in quarantine will get reused regardless of whether there are still references
to it.

In the context of MiraclePtr combined with ASan, it's a problem when:

1. A heap allocation that isn't supported by MiraclePtr is made. At the moment,
   the only such class is allocations made early during the process startup
   before MiraclePtr can be activated.
2. Its address is assigned to a `raw_ptr<T>` variable.
3. The allocation gets freed.
4. A new allocation is made in the same memory region as the first one, but this
   time it is supported.
5. The second allocation gets freed.
6. The `raw_ptr<T>` variable is accessed.

In this case, MiraclePtr will incorrectly assume the memory access is protected.
Luckily, considering the small number of unprotected allocations in Chromium,
the size of the quarantine, and the fact that most reproduction cases take
relatively short time to run, the odds of this happening are very low.

The problem is relatively easy to spot if you look at the ASan report: the
allocation and deallocation stack traces won't be consistent across runs and
the allocation type won't match the use stack trace.

If you encounter a suspicious ASan report, it may be helpful to re-run Chromium
with an increased quarantine capacity as follows:

```
ASAN_OPTIONS=quarantine_size_mb=1024 path/to/chrome
```
