# Use-after-free on error cleanup path

Cleanup or destructor frees objects still reachable via back-references, handles, or mutable gates

_Area: Memory corruption and native code. Seen in 2 disclosed reports; one confirmed bounty: $5,000; latest 2026-03-06. Updated 2026-10-24._

## How it works
Cleanup code assumes that when it runs, every object it frees is unreachable and every pointer it frees is heap-allocated. Error and teardown paths break that assumption: they free objects still referenced elsewhere (back-references, vectors, handles), or free the wrong memory. The gate that decides whether to unregister an object is often a mutable field, so a state change between registration and destruction skips the unregister and leaves a dangling pointer [E1](https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-blog-patch-diff-to-system.md). Cleanup can also run while an update is in flight, freeing a node a later step still reads [E2](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2020-04-google-chrome-display-locking-fuzzing-html.md).

## Where it shows up
- Destructors whose cleanup is conditional on a mutable field (mode, flag, compatibility check) [E1](https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-blog-patch-diff-to-system.md)
- Layout/paint-tree objects removed while an invalidation or update is in flight [E2](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2020-04-google-chrome-display-locking-fuzzing-html.md)
- Error branches that free scratch/stack buffers instead of heap allocations (adjacent wrong-free variant) [E3](https://bugbountylibrary.com/r/h1%3A2621057.md)
- Cleanup loops over arrays where the index was decremented or allocation failed midway

## How to review
For each free/teardown site, ask: is this pointer still reachable from any live structure, and was it actually allocated on the heap? The invariant: every object freed on an error path must have been removed from all back-references and handles first, and the removal must not depend on state that can change after registration. Check that cleanup loops only touch entries that were successfully allocated, and that free() targets match the allocation site (heap vs stack).

## Variants seen
- Destructor skips unregister because IsSuperWetCompatible() flips when LookupMode changes, leaving a dangling vector entry [E1](https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-blog-patch-diff-to-system.md)
- Object removed during in-flight rendersubtree invalidation; later update reads freed PaintLayer [E2](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2020-04-google-chrome-display-locking-fuzzing-html.md)
- free() applied to a stack-local buffer on invalid-input branch (adjacent wrong-free) [E3](https://bugbountylibrary.com/r/h1%3A2621057.md)

## Impact and severity
Ranged from renderer crash [E2](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2020-04-google-chrome-display-locking-fuzzing-html.md) to stack corruption [E3](https://bugbountylibrary.com/r/h1%3A2621057.md) and SYSTEM-level code execution [E1](https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-blog-patch-diff-to-system.md). Severity rises when the freed object is reachable from a privileged component [E1](https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-blog-patch-diff-to-system.md) or when the bug is remotely triggerable via parsed input [E3](https://bugbountylibrary.com/r/h1%3A2621057.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-blog-patch-diff-to-system.md
- E2: https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2020-04-google-chrome-display-locking-fuzzing-html.md
- E3: https://bugbountylibrary.com/r/h1%3A2621057.md
