# DF-4791 — TTM memory-accounting shrinker unbounded recursion → kernel stack exhaustion

## What to run

```
./build.sh          # cc -O2 -Wall -o ttm_shrink_recursion ttm_shrink_recursion.c
./run.sh            # ./ttm_shrink_recursion 64 268435456
```

## Expected output

**On a machine with a radeon- or amdgpu-driven GPU and /dev/dri/card0
readable by the invoking user** (the trigger uses the radeon GEM uapi;
amdgpu has the identical move/populate path):

1. `64 VRAM BOs parked on swap_lru (ttm unpopulated)` — recursion fuel
   (fresh VRAM BOs whose ttm_tt exists but was never populated).
2. `N x 4MiB GTT BOs` — each populated page pushes the TTM kernel zone's
   `used_mem` up by `PAGE_SIZE` until it exceeds `max_mem`
   (`ttm_mem_global_reserve`, ttm_memory.c:477-481).
3. The next accounting-checked allocation enters
   `ttm_mem_global_alloc_zone` → `ttm_shrink` → `ttm_bo_swapout`, which
   picks a phase-1 VRAM BO and moves it to SYSTEM — the move must
   populate the tt, the populate's first `ttm_mem_global_alloc_page`
   re-fails the limit check and calls `ttm_shrink` again, nesting once
   per parked BO (~12 frames / ~1-2 KiB per level vs a 16 KiB kernel
   stack, `UPAGES=4`, sys/cpu/x86_64/include/param.h:126).
4. **Success criterion:** kernel panic / stack-smash splat with a
   backtrace repeating `ttm_shrink` / `ttm_bo_swapout` /
   `ttm_bo_handle_move_mem` / `ttm_pool_populate` frames, or
   non-deterministic corruption of kernel memory adjacent to the
   overflowing thread stack (thread stacks are kmem allocations on
   DragonFly — no guard page).

**On a machine without a DRM device** (this audit guest: QEMU std-VGA):
the run exits 2 at `open()` — recorded in run.log; the defect stands on
the source-level proof in VERDICT.md.

## Files

* `ttm_shrink_recursion.c` — trigger source (self-contained uapi defs)
* `build.sh`, `run.sh` — exact commands
* `build.log`, `run.log` — guest compiler + runtime output (untrimmed)
* `env.txt` — guest state (uname, /dev/dri, vm.dma_reserved)
* `VERDICT.md` — full narrative with the path:line recursion chain
* `fix.diff` — bounded-nesting guard in ttm_memory.c (advisory)
* `manifest.json`, `verdict.json` — machine-readable records
