# DF-4340 — Undefined shift counts throughout the ATOM interpreter (VBIOS-controlled)

**Severity:** Low **Confidence:** certain **File:** sys/dev/drm/radeon/atom.c

## What

Shift counts are untrusted VBIOS values and are used without masking; counts
>= 32 are undefined behaviour (C11 6.5.7):

- `atom_op_shl` (atom.c:937): `dst <<= shift;` — `shift` is a full 32-bit
  ATOM source operand (any value 0..0xFFFFFFFF);
- `atom_op_shr` (atom.c:956): `dst >>= shift;` — same;
- `atom_op_shift_left` (atom.c:904) / `atom_op_shift_right` (atom.c:920):
  `shift` is a VBIOS byte (0..255);
- WS masks (atom.c:252/255): `1 << gctx->shift` with `gctx->shift` a
  VBIOS-written uint8_t (0..255);
- IIO masks (atom.c:125,131,137,147,157): `0xFFFFFFFF >> (32 - CU8(base+1))`
  — width byte 0 gives `>> 32`; `(index|data|io_attr) >> CU8(base+2)` —
  byte shift counts up to 255.

This is not a memory-safety bug by itself: on x86 the counts are masked
mod 32 at runtime — *when the compiler emits a runtime shift*. The guest
demo shows gcc 8.3 -O1 instead **constant-folds one instance to 0**
(`0xffff << 40` → `0x00000000`), i.e. the computed GPU programming values
are compiler-dependent garbage for out-of-range counts. Hardening with
defined semantics (>= width ⇒ 0) makes behavior portable and predictable.

## Reproduce (logic level)

```
cc -O1 -g -o atom_harness atom_harness.c && ./atom_harness shift
# -> (0xffff << 40)=0x00000000 vs (0xffff << 8)=0x00ffff00 -> divergent
#    IIO mask width=0: >>32 gives 0x12345678 (UB relied upon)
```

## Fix

`fix.diff` (git-apply checked): `atom_shl/atom_shr` helpers implementing
defined semantics, applied to the four shift opcodes and the two WS masks.
(The IIO mask sites are inside atom_iio_execute and can use the same
helpers; left as noted because that function is also touched by DF-4337.)
