# DF-4681 — ar2317: numPdGainsUsed==0 → uint32-wrapped wild reads + uninit stack

Twin of DF-4620 (ar5413) / DF-4649 (ar2316) / DF-4661 (ar2413), verified for
`sys/dev/netif/ath/ath_hal/ar5212/ar2317.c`.

## Build

Same harness as DF-4680: `cd /root/df2317 && sh build.sh`

## Run

```
./ar2317_harness 2
sh run.sh          # includes 3 extra runs showing minPower uninit variance
```

## Expected (baseline)

```
mapped wild pages ... seeded 0x5A5A
gainBoundaries[0] = 0x5a5a
pcdacTable[0] = 0x5a5a
minPower out = 0xd4a0   (varies run-to-run)
DF-4681 REPRODUCED: uint32-underflow wild reads at ar2317.c:465/:469 + uninit
stack read at :405
```

With an EEPROM whose xpd_mask is 0 (all `numVpd == 0`, the exact dataset shape
the shared `SetupRawDataset` produces, ah_eeprom_v3.c:656-673),
`numPdGainsUsed` stays 0; `HALASSERT(1 <= numPdGainsUsed ...)` at :516 is
compiled out in release (ah_internal.h:665-676) and the caller (:513-515)
ignores the return, so:

- :465 `pPdGainBoundaries[ii-1]` with `ii==0` (uint32) → element 0xFFFFFFFF →
  read at `gb + 0x1FFFFFFFE` (+8.59 GB)
- :469 `pPDADCValues[kk-1]` with `kk==0` → same wrap from pcdacTable
- :405 `*pMinCalPower = Pmin_t2[0]` reads uninitialized stack

The harness maps the exact wild pages (kernel-direct-map emulation), seeds
0x5A5A, and shows both values propagate into outputs that reach hardware:
`gainBoundaries[0]` → AR_PHY_TPCRG5 (ar2317SetPowerTable:575-580),
`pcdacTable[0]` → 32 PHY register writes (:566-573).

## Fix validation

`fix.diff` = early `return 0` when numPdGainsUsed==0 (before the Pmin_t2[0]
read) + `numPdGainsUsed < 1 → AH_FALSE` in ar2317SetPowerTable. Patched mode 2
(fix_run.log): `ret=0`, `minPower=0x7c7c` (sentinel), `gainBoundaries[0]=0x0000`,
`pcdacTable[0]=0xaaaa` (canary intact) — no wild reads, no uninit read.

Not re-reported: DF-1806 (numChannels==0, pass 1) — different trigger/guard.
