# DF-4846 — feeder_format.c FXROUND align-overshoot (evidence pack)

## What this proves

`sys/dev/sound/pcm/feeder_format.c` sizes its feed window with the build-time
generated fast-division macros (`SND_FXROUND`/`SND_FXDIV` from
`sys/tools/sound/snd_fxdiv_gen.awk`). The generated table is inexact **within
its own claimed domain [1, 65536]** for every non-power-of-2 divisor: it
misrounds UP (FXDIV = floor+1) for 15–40% of count values, starting as low as
x≈4694 (align 15), 5473 (align 14), 8195 (align 12). Consequences, each proven
by this harness on the REAL, UNMODIFIED file with the REAL generated header:

- **T1** `feeder_format.c:220` `count = SND_FXROUND(count, info->oalign)` can
  EXCEED the caller's count → the whole pass is sized past the destination
  window → the source feeder writes past the window (REAR guard hit) and the
  return value exceeds count (in-kernel: `sndbuf_acquire()` ring overflow,
  buffer.c:615-636, only KASSERT-protected).
- **T2** `feeder_format.c:233` (ialign>oalign) `j = SND_FXROUND(count,
  ialign)` can exceed count → `src = dst + count - j < dst` (write BEFORE the
  window) and the source window exceeds the destination.
- **T3** `feeder_format.c:240` `SND_FXDIV(ret, ialign)` on a partial source
  return miscounts a frame up → the feeder converts and reports more output
  bytes than the source delivered (return inflation into sndbuf_acquire).

## Build / run (guest)

```
cd /root/fx && sh build.sh      # regenerates snd_fxdiv_gen.h via the real awk,
                                # copies real headers + the 4 feeder files, builds
./fxfmt                         # baseline: FAIL (8315/28200 checks)
cp snd_fxdiv_gen_fixed.h snd_fxdiv_gen.h && cc -O1 -g -o fxfmt_fixed fxfmt.c fxsrc.c
./fxfmt_fixed                   # fixed table: ALL PASS
```

## Expected output

baseline `fmt.log`: `fxfmt: checks=28200 failures=8315 -> FAIL` with
`FAIL[T1 ...] REAR guard (write past window)` / `return > count` lines.
fixed `fmt_fixed.log`: `failures=0 -> ALL PASS`.

## In-kernel reachability (traced, path:line)

- Chain insert: `feeder_chain.c:139-173` (feeder_build_format) on any
  encoding mismatch — ordinary unprivileged `SNDCTL_DSP_SETFMT` choice.
- Counts: `buffer.c:705-709` `maxfeed = SND_FXROUND(SND_FXDIV_MAX, align)`,
  `count = min(free, maxfeed)` — free is arbitrary (user-paced), so bad
  residues ≥ first_bad occur routinely on 8K–64K buffers.
- Return path: `buffer.c:712` `sndbuf_acquire(to, tmpbuf, cnt)` with
  cnt > free → ring write past free region, `rl` inflated past `bufsize`
  (`sndbuf_getfree = bufsize - rl` goes unsigned-negative).
- 64KB-exact tmpbuf (`buffer.c:226` kmalloc(round_page(65536))) makes the
  T1/T2 write a heap OOB write past the allocation.

In-kernel churn (ES1370, 6ch+7ch vchans, bad-residue pacing) showed no
differential anomaly vs aligned control on this production (no-INVARIANTS)
kernel — see DF-4849 pack `churn_*.log`. Feeder-level proof is decisive.

## Fix

`fix.diff` — fix the generator (`snd_fxdiv_gen.awk`) so the magic reciprocal
is exact across the whole claimed domain (grow shift until
`(d*mul - 2^z) * 65536 < 2^z`) and emit a 64-bit multiply (the required
magics no longer fit a 16-bit multiplier). Exhaustively verified for all 44
table divisors over [1,65536]; all four feeder harnesses (format/matrix/
volume/mixer) go FAIL→ALL PASS with the regenerated header.
