# GC mark phase dereferences invalid object

Mark/scan routines walking context stacks or instance tables without liveness or null checks

_Area: Memory corruption and native code. Seen in 2 disclosed reports; one confirmed bounty: $800; latest 2017-03-14. Updated 2026-10-31._

## How it works
A garbage collector's mark phase assumes every pointer it reaches is either a live, well-formed object or a recognizable free/nil slot. That assumption breaks when a partially-initialized or dematerialized object is still reachable: the mark routine walks a context stack or instance-variable table and dereferences a pointer that is nil, freed, or points at a sub-allocation whose owner was optimized away. The collector has no liveness check before touching the object header, so the dereference faults or reads attacker-influenced memory.

## Where it shows up
- Mark/scan functions that read an object header or table pointer without first testing for nil or a free tag (e.g. a `MRB_TT_FREE` path, `t=0x17`).
- Context-stack or instance-table walkers reached during incremental marking, where objects may be only partly initialized.
- Escape analysis that dematerializes an object but keeps a backing store alive, plus any path that materializes the same activation more than once.
- Parser/VM error paths (malformed class inheritance, rescue, operator soup) that leave stack slots uninitialized before GC runs.

## How to review
For every mark/scan routine, confirm the invariant: before dereferencing any object or table pointer, the code checks the pointer is non-nil and its type tag is a live, initialized type; free or unknown tags are skipped, not followed. Check that materialization paths cannot produce two objects sharing one backing store, and that error/parse paths zero or tag stack slots before they become GC-reachable. Trace what happens when a value with an unexpected tag reaches the walker.

## Variants seen
- GC mark phase dereferences a nil/free RBasic pointer while scanning the context stack [E2](https://bugbountylibrary.com/r/h1%3A208526.md).
- Invalid instance-variable table pointer dereferenced in `mark_tbl()` during incremental marking [E3](https://bugbountylibrary.com/r/h1%3A183239.md).
- Escape analysis dematerializes an ArgumentsObject but keeps its backing store, so repeated materialization yields two objects sharing it [E1](https://bugbountylibrary.com/r/p0%3ACVE-2022-1364.md).

## Impact and severity
Crashes (DoS) of embedded interpreter sandboxes [E2](https://bugbountylibrary.com/r/h1%3A208526.md)[E3](https://bugbountylibrary.com/r/h1%3A183239.md); in the V8 case a hole-value leak from shared backing store, a memory-disclosure primitive in a browser renderer [E1](https://bugbountylibrary.com/r/p0%3ACVE-2022-1364.md). Severity rises when the bad pointer is attacker-influenced rather than merely nil, and when the target is a sandbox boundary.

## Why fixes fail
Evidence shows GC-time crashes surfacing only under specific constructs (`Array.dup.new`, nested blocks) [E3](https://bugbountylibrary.com/r/h1%3A183239.md), so fixes that patch one parse path leave other partially-initialized reachable objects; the underlying missing liveness check recurs.

## Evidence
- E1: https://bugbountylibrary.com/r/p0%3ACVE-2022-1364.md
- E2: https://bugbountylibrary.com/r/h1%3A208526.md
- E3: https://bugbountylibrary.com/r/h1%3A183239.md
