blob: 3026c73888805d25529052cf356dc2a7629789b6 [file] [view] [edit]
# Dangling Pointer Detector
A pointer is dangling when it references freed memory. Dangling pointers are
a source of Use-After-Free (UAF) bugs and are highly discouraged unless you can
definitively ensure that they will never be dereferenced or used after the
pointed-to object is freed.
ANGLE tests (run via `TestSuite`) are configured to detect dangling
`raw_ptr<T>` instances when built with PartitionAlloc enabled.
## Motivation
Tracking the lifetime of interacting objects across a complex C++ codebase is
difficult. Often, lifetime issues are discovered late when they cause
hard-to-reproduce user crashes.
Enforcing the Dangling Pointer Detector on the Commit Queue (CQ) helps us:
1. **Prevent Regressions**: Catch accidental lifetime changes that invalidate
prior ownership assumptions before they ship.
2. **Promote Better Architecture**: Flag ambiguous object lifetimes during code
review.
3. **Verify Cleanups**: Give developers immediate confirmation when cleaning
up dangling pointers.
## `raw_ptr<T>`
A `raw_ptr<T>` is a non-owning smart pointer. When using `raw_ptr<T>`, the
severity of UAFs is significantly mitigated because the underlying allocation
is protected by [MiraclePtr / BackupRefPtr](https://security.googleblog.com/2022/09/use-after-freedom-miracleptr.html).
A `raw_ptr<T>` works transparently like a raw `T*`. It should primarily be used
for class and struct member variables.
## Flavors & Annotations
When a pointer must temporarily dangle safely, or represents an untriaged legacy
instance, you can use these annotations:
```cpp
raw_ptr<T> ptr_never_dangling;
raw_ptr<T, DisableDanglingPtrDetection> ptr_allowed_to_dangle;
raw_ptr<T, DanglingUntriaged> ptr_dangling_to_investigate;
```
* `DisableDanglingPtrDetection`: Used to annotate intentional and safe dangling
pointers as a last resort if re-architecting ownership is impractical.
* `DanglingUntriaged`: Indicates a pre-existing dangling pointer marked for
future cleanup.
## Diagnosing Dangling Pointers
When a dangling pointer release is detected in ANGLE standalone builds,
the test runner aborts with a crash backtrace at the point where the
`raw_ptr` was released (reassigned, cleared, or destructed).
The callbacks are registered in [`src/tests/test_utils/runner/PartitionAllocSupport.cpp`](../src/tests/test_utils/runner/PartitionAllocSupport.cpp):
1. `SetDanglingRawPtrDetectedFn`: Invoked when memory is freed while a
`raw_ptr` still references it.
2. `SetDanglingRawPtrReleasedFn`: Invoked when the dangling `raw_ptr` is released,
aborting the process with `FATAL()`.
To find where the pointed-to memory was **freed**:
Run the test under a debugger (`gdb` or `lldb`) and place a breakpoint inside
`SetDanglingRawPtrDetectedFn` in `PartitionAllocSupport.cpp`. The call stack
at that breakpoint reveals the exact code path freeing the memory.
*(Note: Chromium tests exercising ANGLE use Chrome's test runner, which
automatically records and displays both the memory-free stacktrace and the
`raw_ptr` release stacktrace.)*
## Enabling PartitionAlloc in Standalone Builds
PartitionAlloc is enabled by default on ANGLE CQ bots for assert builds.
To enable it locally in standalone ANGLE builds:
1. Add `"checkout_angle_partition_alloc": True` to `custom_vars` in your `.gclient` file:
```python
solutions = [
{
"name": ".",
"url": "https://chromium.googlesource.com/angle/angle.git",
"custom_vars": {
"checkout_angle_partition_alloc": True,
},
},
]
```
2. Run `gclient sync` to fetch PartitionAlloc into `third_party/partition_alloc`.
3. In assert-enabled builds (`dcheck_always_on = true` or `is_debug = true`), PartitionAlloc is enabled automatically. You can also explicitly set `angle_use_partition_alloc = true` in `args.gn`.