| # Dangling Pointer Detector | |
| A pointer is dangling when it references freed memory. Typical examples can be | |
| found [here](https://docs.google.com/document/d/11YYsyPF9rQv_QFf982Khie3YuNPXV0NdhzJPojpZfco/edit?resourcekey=0-h1dr1uDzZGU7YWHth5TRAQ#heading=h.wxt96wl0k0sq). | |
| Dangling pointers are not a problem unless they are subsequently dereferenced | |
| and/or used for other purposes. Proving that pointers are unused has turned out | |
| to be difficult in general, especially in face of future modifications to | |
| the code. Hence, they are a source of UaF bugs and highly discouraged unless | |
| you are able to ensure that they can never be used after the pointed-to objects | |
| are freed. | |
| See also the [Dangling Pointers Guide](./dangling_ptr_guide.md) for how to fix | |
| cases where dangling pointers occur. | |
| Behind build flags, Chrome implements a dangling pointer detector. It causes | |
| Chrome to crash, whenever a raw_ptr becomes dangling: | |
| ```cpp | |
| raw_ptr<T> ptr_never_dangling; | |
| ``` | |
| On the other hand, we cannot simply ban all the usage of dangling pointers | |
| because there are valid use cases. The `DisableDanglingPtrDetection` option can | |
| be used to annotate "intentional-and-safe" dangling pointers. It is meant to be | |
| used as a last resort, only if there is no better way to re-architecture the | |
| code. | |
| ```cpp | |
| raw_ptr<T, DisableDanglingPtrDetection> ptr_may_dangle; | |
| ``` | |
| For more details on available traits, see | |
| [RawPtrTraits](../base/memory/raw_ptr.md#RawPtrTraits). | |
| The `DanglingUntriaged` option has been used to annotate pre-existing dangling | |
| pointers in Chrome: | |
| ```cpp | |
| raw_ptr<T, DanglingUntriaged> ptr_dangling_mysteriously; | |
| ``` | |
| Contrary to `DisableDanglingPtrDetection`, we don't know yet why it dangles. It | |
| is meant to be either refactored to avoid dangling, or turned into | |
| "DisableDanglingPtrDetection" with a comment explaining what happens. | |
| # How to check for dangling pointers? | |
| On **Linux**, it is **enabled by default** on most configurations. | |
| To be precise: (`is_debug` or `dcheck_always_on`) and non `is_official` builds. | |
| For the other operating systems, this is gated by both build and runtime flags: | |
| ## Build flags | |
| ```bash | |
| gn args ./out/dangling/ | |
| ``` | |
| ```gn | |
| use_remoteexec = true | |
| is_debug = false # Important! (*) | |
| is_component_build = false # Important! (*) | |
| dcheck_always_on = true | |
| enable_backup_ref_ptr_support = true # true by default on some platforms | |
| enable_dangling_raw_ptr_checks = true | |
| ``` | |
| (*) We want to emphasize that setting either `is_debug = false` or | |
| `is_component_build = false` is important. It is a common mistake to set | |
| `is_debug` to `true`, which in turn turns on component builds, which | |
| disables PartitionAlloc-Everywhere. `enable_backup_ref_ptr_support = true` can't | |
| be used without PartitionAlloc-Everywhere, and is silently set to `false`. | |
| ## Runtime flags | |
| ```bash | |
| ./out/dangling/content_shell \ | |
| --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr | |
| ``` | |
| By default, Chrome will crash on the first dangling raw_ptr detected. | |
| # Runtime flags options: | |
| ## Mode parameter | |
| ### Crash (default) | |
| ```bash | |
| --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:mode/crash | |
| ``` | |
| ### Record a list of signatures | |
| Example usage: | |
| ```bash | |
| ./out/dangling/content_shell \ | |
| --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:mode/log_only \ | |
| |& tee output | |
| ``` | |
| The logs can be filtered and transformed into a tab separated table: | |
| ```bash | |
| cat output \ | |
| | grep "[DanglingSignature]" \ | |
| | cut -f2,3,4,5 \ | |
| | sort \ | |
| | uniq -c \ | |
| | sed -E 's/^ *//; s/ /\t/' \ | |
| | sort -rn | |
| ``` | |
| This is used to list issues and track progresses. | |
| ## Type parameter | |
| ### Select all dangling raw_ptr (default) | |
| The option: `type/all` selects every dangling pointer. | |
| Example usage: | |
| ```bash | |
| ./out/dangling/content_shell \ | |
| --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:type/all | |
| ``` | |
| ### Select cross tasks dangling raw_ptr | |
| The option: `type/cross_task` selects dangling pointers that are released in a | |
| different task than the one where the memory was freed. Those are more likely to | |
| cause UAF. | |
| Example usage: | |
| ```bash | |
| ./out/dangling/content_shell \ | |
| --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:type/cross_task | |
| ``` | |
| ### Combination | |
| Both parameters can be combined, example usage: | |
| ```bash | |
| ./out/dangling/content_shell \ | |
| --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:mode/log_only/type/cross_task \ | |
| |& tee output | |
| ``` | |
| # Alternative dangling pointer detector (experimental) | |
| The dangling pointer detector above works only against certain heap allocated | |
| objects, but there is an alternate form that catches other cases such as | |
| pointers to out-of-scope stack variables or pointers to deallocated shared | |
| memory regions. The GN arguments to enable it are: | |
| ```gn | |
| enable_backup_ref_ptr_support=false | |
| is_asan=true | |
| is_component_build=false | |
| is_debug=false | |
| dcheck_always_on = true | |
| use_asan_backup_ref_ptr=false | |
| use_raw_ptr_asan_unowned_impl=true | |
| ``` | |
| This will crash when the object containing the dangling ptr is destructed, | |
| giving the usual three-stack trace from ASAN showing where the deleted object | |
| was allocated and freed. | |
| When running under this mode, there is no need to specify any --enable-features | |
| flag as above. |