--- slug: miracle-ptr type: decision summary: "The decision to turn many browser-process use-after-free bugs into crashes or memory leaks by replacing unowned C++ pointer fields with raw_ptr backed by BackupRefPtr in PartitionAlloc." created: 2026-06-20 updated: 2026-06-20 last_link_verified: 2026-06-20 related: exploit-chain: relation: mitigates note: "MiraclePtr reduces the exploitable population of browser-process use-after-free links by keeping freed PartitionAlloc memory quarantined while a dangling raw_ptr still refers to it." escape-chain: relation: mitigates note: "The sandbox escape chain's browser-process link often depends on a temporal-memory-safety bug; MiraclePtr changes many of those bugs from code-execution primitives into crashes or leaks." browser-renderer-split: relation: builds-on note: "The mitigation matters most because the browser process holds the privileges the renderer lacks; a browser-process use-after-free gives attackers more reach than a contained renderer bug." untrusted-renderer-axiom: relation: complements note: "The axiom keeps renderer claims hostile at the IPC boundary, while MiraclePtr hardens the browser-process C++ heap that processes those claims." v8-heap-sandbox: relation: complements note: "The V8 Heap Sandbox contains corruption inside the JavaScript heap; MiraclePtr is a separate temporal-safety decision for Chromium C++ objects allocated through PartitionAlloc." mseal-forward-cfi: relation: complements note: "mseal-Based Forward-Edge CFI narrows control-flow hijack after a renderer primitive, while MiraclePtr narrows temporal-memory-safety exploitation in non-renderer Chromium C++." memory-pressure-response: relation: contrasts-with note: "MiraclePtr spends memory to buy temporal safety, while Memory Pressure Response describes the runtime moves Chromium makes when memory budget is already tight." supply-chain-lag: relation: informs note: "Downstream Chromium consumers inherit MiraclePtr only when they consume builds with BackupRefPtr enabled for the relevant process class; lagging versions may keep the older raw-pointer exposure." --- # MiraclePtr (BackupRefPtr) > **Decision** > > A one-time architectural or governance choice whose consequences still govern current work. *The decision to wrap many non-owning C++ pointer fields in `raw_ptr`, whose BackupRefPtr implementation uses PartitionAlloc metadata to keep freed allocations unavailable while dangling references still exist.* The names are easy to blur. MiraclePtr is the umbrella project name, BackupRefPtr is the shipped allocator-backed algorithm, and `raw_ptr` is the type a Chromium contributor writes in code. The entry's security claim depends on keeping those three levels separate. Use-after-free bugs remain useful to attackers after Chromium's process model has done its job. A renderer compromise is contained by the renderer sandbox; a browser-process use-after-free can sit on the privileged side of that split, close to cookies, profile data, file-system brokering, and IPC handlers. MiraclePtr is the Chromium project's decision to make that bug class less exploitable in the existing C++ codebase without waiting for a full rewrite. ## Decision Statement Chromium chose to mitigate a large share of use-after-free bugs in existing C++ by replacing many unowned raw pointer fields with `raw_ptr`. The type is a non-owning smart pointer whose BackupRefPtr implementation stores reference-count metadata in PartitionAlloc and quarantines freed allocations while any `raw_ptr` still points at them. ## Context Temporal memory safety is the property that an address still refers to the object the program believes it refers to. A use-after-free violates that property: code frees an object, leaves a pointer behind, and later reads or writes through the stale pointer after the allocator has reused the memory for something else. In a browser, that stale pointer can become an attacker-shaped type confusion, a fake vtable, or a wrong object header at exactly the point where the privileged browser process is handling renderer-supplied data. The long-term answer is to write less memory-unsafe C++. Chromium is doing that through Rust adoption, spanification of unsafe buffers, V8-specific containment, and process isolation. None of those removes the existing browser-process C++ heap. The project needed a retrofit: something deployable across millions of lines, compatible with ordinary C++ class fields, and narrow enough that the team could roll it out in the codebase while Chrome kept shipping on its four-week stable cadence. The first major stable rollout enabled BackupRefPtr for the browser process on Windows and Android in Chrome 102. The current `raw_ptr` reference documents protection as default-on in non-renderer processes on Android, Windows, ChromeOS, macOS, Linux, and Fuchsia, with exceptions for iOS and Linux CastOS. Renderer-only code remains the hardest boundary because the renderer is hot, attacker-influenced, and performance-sensitive. ## Alternatives Considered | Alternative | Description | Reason rejected | |---|---|---| | Keep raw `T*` fields plus review discipline | Continue using ordinary non-owning C++ pointers and rely on code review, tests, fuzzing, and AddressSanitizer-style discovery to catch lifetime errors. | Review finds individual bugs; it doesn't change the exploitability of the class. A large C++ codebase keeps creating new lifetime edges, and a privileged browser-process use-after-free remains a high-value link in an exploit chain. | | *Scan heap quarantine | Put freed memory in quarantine, scan the heap for remaining references, and release a block only after the scanner finds no pointers into it. | The May 2022 Google Security blog experiment found meaningful memory cost in renderer-process tests: about 12 percent memory regression for *Scan without hardware help. The scanner also has race and scheduling complexity because it has to inspect a mutating heap. | | Hardware Memory Tagging Extension | Use ARM MTE tags to detect stale pointers when the pointer tag no longer matches the allocation tag. | MTE depends on hardware support that Chromium cannot assume across its installed base. The published prototype results were promising, but the project still needed a software mechanism for devices without MTE and for platforms outside that hardware family. | | BackupRefPtr through `raw_ptr` (chosen) | Add ref-count metadata to PartitionAlloc allocations, replace eligible non-owning pointer fields with `raw_ptr`, and quarantine freed memory while dangling references remain. | It required no new hardware, fit existing C++ field declarations, could be enforced by tooling, and gave the project a measurable reduction in exploitability while preserving most call-site behavior. The cost moved into memory overhead and pointer construction, assignment, and destruction rather than into every dereference. | ## Rationale The chosen design changed the outcome of the bug class without pretending to solve ownership. `raw_ptr` is still non-owning. The owner still frees the object at the correct time, and dereferencing a dangling `raw_ptr` is still undefined behavior. The security gain is narrower: when the owner frees a PartitionAlloc-backed object and a `raw_ptr` still points at it, BackupRefPtr keeps the allocation out of reuse and poisons it with the `0xEF` pattern. The stale access is more likely to crash or leak memory than to become a controlled write into a new attacker-shaped object. That narrowness is why the retrofit worked. In most class and struct fields, the code change is a type replacement: `T* member_` becomes `raw_ptr member_`. The type keeps the pointer-sized representation, supports ordinary dereference and arrow access, and avoids adding cost to the dereference itself. The cost appears when the pointer is constructed, assigned, moved, or destroyed, because BackupRefPtr has to maintain allocator-side metadata and check that pointer arithmetic stays within the allocation. The decision also kept the rollout enforceable. Chromium's style guide and Clang plugin steer eligible class and struct fields toward `raw_ptr`, with named escape hatches such as `RAW_PTR_EXCLUSION` for cases that cannot compile, point outside protected memory, sit in renderer-only paths, or have measured performance regressions. An escape hatch is not a second design path. It is a documented exception that reviewers can audit. ## Ongoing Consequences For Chromium contributors, the rule is now visible in code review. A non-owning class or struct field in non-renderer Chromium C++ is expected to use `raw_ptr` unless one of the documented exceptions applies. Function pointers, Objective-C object pointers, pointers into stack memory, shared memory, `mmap` regions, V8 heaps, Oilpan heaps, Java heaps, and other non-PartitionAlloc-managed memory are not protected by BackupRefPtr and may need a different representation or a documented exclusion. The pointer's ownership story still has to be correct; MiraclePtr doesn't turn a borrower into an owner. For security response, the change lowers the value of a browser-process use-after-free. The September 2022 Google Security blog post described MiraclePtr as protecting roughly half of known exploitable use-after-free issues against exploitation. That doesn't mean half of lifetime bugs disappeared. It means many stale accesses that would once have reached attacker-controlled replacement memory instead hit quarantined or poisoned memory and crash in a way the project can debug. For performance and memory budgets, the decision spends some of the savings PartitionAlloc produced elsewhere. The 2022 rollout account reported browser-process memory increases in the low single digits, with the Google post naming about 4.5 to 6.5 percent on Windows and about 3.5 to 5 percent on Android. The same post notes that PartitionAlloc work had recently produced larger memory savings, so the project spent part of that budget on temporal safety. That exchange matters for downstream products: on memory-constrained fleets, MiraclePtr's cost lives beside [Memory Pressure Response](memory-pressure-response.md), tab discard rate, and process-consolidation thresholds. For exploit-chain reasoning, MiraclePtr mostly hardens the browser-process link. A renderer-side V8 bug still has its own containment story in the [V8 Heap Sandbox](v8-heap-sandbox.md), trusted-space partitioning, CFI, and site/process isolation. A browser-process use-after-free in a Mojo handler is different. It is close to the third link of the [Sandbox Escape Chain](escape-chain.md), the point where a renderer primitive tries to cross into privileged code. MiraclePtr makes that link harder to turn into controlled memory reuse. For downstream Chromium consumers, the decision is inherited only when the product consumes the relevant Chromium version, build flags, allocator configuration, and process class. A fork that carries custom browser-process C++ with ordinary `T*` fields can reintroduce the older exposure even while upstream has moved. An Electron, WebView2, enterprise-browser, or embedded-runtime team auditing custom code should treat `RAW_PTR_EXCLUSION` and `RawPtrManualPathsToIgnore.h` entries as security debt unless the exception is mechanical and documented. The decision also creates a debugging obligation. A crash inside `RawPtrBackupRefImpl::AcquireInternal()` or `ReleaseInternal()` is not noise to be papered over with a cast or an exclusion. It is often the runtime signal that a pointer lifetime assumption was false. The right response is to fix the lifetime model or use the documented short-lived adapter for an in-out argument, not to restore a raw pointer because the raw pointer compiled. ## Reversal Conditions The decision could be revisited if a stronger temporal-safety mechanism became deployable across Chromium's supported platforms at lower cost. Universal hardware memory tagging with deterministic properties would qualify, but today's MTE story is platform-bound and still needs software fallback. A memory-safe rewrite of the browser-process C++ surface would also qualify, but that is a multi-year migration rather than a replacement for a retrofit. The decision could also be narrowed if its overhead stopped fitting the product budget. That would require a measured regression severe enough that the project could not recover the cost through allocator work, process tuning, or targeted exceptions. The current direction points the other way: Chromium's 2026 quarterly security updates describe continuing memory-safety work around PartitionAlloc, Skia, Rust, and Safe Buffers rather than a retreat from MiraclePtr. What should not trigger reversal is a single false positive or a local compile problem. The `raw_ptr` reference already documents recoverable compile-time problems, `kMayDangle` aliases for known legacy patterns, and explicit exclusions for unsupported cases. Those are local escape valves around a standing decision, not reasons to abandon the decision. ## Notes for Agent Context When editing Chromium C++ outside renderer-only paths, use `raw_ptr` for non-owning class and struct fields that point to PartitionAlloc-managed heap objects. Don't use `raw_ptr` to express ownership: use `std::unique_ptr`, `scoped_refptr`, or another owning type when the field owns the object, and keep lifetime analysis explicit because `raw_ptr` doesn't free the pointee. Don't add `RAW_PTR_EXCLUSION`, `RawPtrManualPathsToIgnore.h`, `DisableDanglingPtrDetection`, or `DanglingUntriaged` unless the documented exception applies and the reason is written next to the field. When an API needs a `T**` or `T*&` out parameter, don't take the address of a `raw_ptr` directly; refactor the callee to accept `raw_ptr*` or use `AsEphemeralRawAddr()` only for the one full expression the reference permits. ## Sources The canonical implementation reference is Chromium's own `base/memory/raw_ptr.md`, whose current title names the type as `raw_ptr` and the aliases MiraclePtr, BackupRefPtr, and BRP. It documents the quick rules, the non-owning semantics, the BackupRefPtr quarantine-and-poison mechanism, the default process coverage, and the documented exception paths. The public decision record is the Google Online Security Blog post *Use-after-freedom: MiraclePtr* by Adrian Taylor, Bartek Nowierski, and Kentaro Hara on behalf of the MiraclePtr team, published September 13, 2022. It records the Chrome 102 browser-process rollout on Windows and Android, the rough use-after-free coverage target, the memory-overhead tradeoff, and the browser-process focus. The main rejected-alternative record is the Google Online Security Blog post *Retrofitting Temporal Memory Safety on C++* by Anton Bikineev, Michael Lippautz, and Hannes Payer, published May 26, 2022. It explains the *Scan heap-scanning family, the renderer-process memory regression observed in experiments, and the MTE prototype results that made hardware tagging promising but insufficient as the general rollout answer. Chromium's Security Quarterly Updates provide the current deployment ledger. The Q4 2025 and Q1 2026 entries place MiraclePtr beside spanification, Rust migration, V8 sandbox hardening, and PartitionAlloc adoption in dependencies such as Skia. That ledger is useful because MiraclePtr is a living mitigation, not a one-time blog post. ## Technical Drill-Down - [`base/memory/raw_ptr.md` (pinned `d009a0e`)](https://chromium.googlesource.com/chromium/src/+/d009a0ed912550c51a86308b07a275d5eeb33ac8/base/memory/raw_ptr.md) — the contributor-facing reference for `raw_ptr` usage, exceptions, performance notes, and dangling-pointer detection. - [`base/memory/raw_ptr.h` (pinned `d009a0e`)](https://chromium.googlesource.com/chromium/src/+/d009a0ed912550c51a86308b07a275d5eeb33ac8/base/memory/raw_ptr.h) — the wrapper type and trait surface Chromium code includes. - [`build_overrides/partition_alloc.gni` (pinned `d009a0e`)](https://chromium.googlesource.com/chromium/src/+/d009a0ed912550c51a86308b07a275d5eeb33ac8/build_overrides/partition_alloc.gni) — one of the build-argument sources the `raw_ptr` reference names for BackupRefPtr support and feature-flag state. - [`base/allocator/partition_allocator/partition_alloc.gni` (pinned `d009a0e`)](https://chromium.googlesource.com/chromium/src/+/d009a0ed912550c51a86308b07a275d5eeb33ac8/base/allocator/partition_allocator/partition_alloc.gni) — allocator build configuration for the PartitionAlloc features BackupRefPtr depends on. - [`tools/clang/raw_ptr_plugin/RawPtrManualPathsToIgnore.h` (pinned `d009a0e`)](https://chromium.googlesource.com/chromium/src/+/d009a0ed912550c51a86308b07a275d5eeb33ac8/tools/clang/raw_ptr_plugin/RawPtrManualPathsToIgnore.h) — the directory-level exclusion mechanism; any use here should be treated as a reviewable exception, not a default. - [`docs/dangling_ptr.md` (pinned `d009a0e`)](https://chromium.googlesource.com/chromium/src/+/d009a0ed912550c51a86308b07a275d5eeb33ac8/docs/dangling_ptr.md) — the dangling-pointer detection guide referenced by `raw_ptr` for `kMayDangle` and related aliases. - [Google Online Security Blog: *Use-after-freedom: MiraclePtr*, September 2022](https://security.googleblog.com/2022/09/use-after-freedom-miracleptr.html) — public rollout rationale, coverage claim, and memory-overhead tradeoff. - [Google Online Security Blog: *Retrofitting Temporal Memory Safety on C++*, May 2022](https://security.googleblog.com/2022/05/retrofitting-temporal-memory-safety-on-c.html) — *Scan and MTE experimental context, including why heap scanning and hardware tagging did not become the general retrofit on their own. - [Chromium Security Quarterly Updates](https://www.chromium.org/Home/chromium-security/quarterly-updates/) — ongoing deployment ledger for memory-safety work around PartitionAlloc, Skia, Rust, Safe Buffers, and V8 hardening. --- - [Next: Spanification and the Unsafe Buffers Discipline](spanification-unsafe-buffers.md) - [Previous: Rust in Chromium](rust-chromium.md)