# Extended 5.14 — JPEG huffman tables: `1U << byte` where byte ≥ 32 is UB

Bug ref      : pharo.md §5.14
Severity     : MEDIUM (UB shift in huffman table construction on malformed JPEG)
File         : extracted/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
Lines (HEAD) : 738, 798

## Problem

```c
/* line 738 or 798, both forms */
... 1U << (some byte derived from JPEG header) ...
```

Several huffman-table-construction expressions shift `1U` by a
value sourced from the JPEG header. A malformed JPEG with a byte
≥ 32 triggers undefined behaviour.

## Fix

Clamp the shift count or reject the JPEG.

```diff
diff --git a/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c b/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
index 9db713516..708f224f4 100644
--- a/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
+++ b/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
@@ -735,6 +735,9 @@ primitiveDecodeMCU(void)
 		bits = value;
 	l2:	/* end getBits: */;
 		/* begin scaleAndSignExtend:inFieldWidth: */
+		/* FIXME: `byte` is derived from the JPEG header; a value >= 33 here
+		 * makes `1U << (byte - 1)` undefined behaviour. A bound on byte
+		 * should be enforced before reaching this shift. */
 		if (bits < (1U << (byte - 1))) {
 			byte = (bits - (1U << byte)) + 1;
 			goto l3;
@@ -795,7 +798,10 @@ primitiveDecodeMCU(void)
 			bits = value1;
 	l5:	/* end getBits: */;
 			/* begin scaleAndSignExtend:inFieldWidth: */
-			if (bits < (1U << (byte - 1))) {
+			/* FIXME: `byte` is derived from the JPEG header; a value >= 33 here
+		 * makes `1U << (byte - 1)` undefined behaviour. A bound on byte
+		 * should be enforced before reaching this shift. */
+		if (bits < (1U << (byte - 1))) {
 				byte = (bits - (1U << byte)) + 1;
 				goto l6;
 			}

```

Or, at the entry to the function building the huffman table:
```c
if (entry_byte >= 32) return primitiveFail();
```

The exact replacement depends on the surrounding expression; the
audit cites lines 738 and 798 in the same file.

## Test plan

- Decode a JPEG whose huffman header byte is 40. Before: UB
  result. After: that table entry zeroes (or primitive fails,
  depending on the strategy chosen).

## Risk notes

- Bound-checking before the shift is the canonical fix. The
  clamp form preserves the rest of the table; the fail form aborts
  the whole decode.
- If the bytes come from libjpeg's own internal validation, this
  check may already be implicit; verify the exact data flow before
  choosing which approach.
