# Extended 4.5 — JPEGReader: divide-by-zero on partial-zero scale

Bug ref      : pharo.md §4.5
Severity     : MEDIUM (SIGFPE on malformed JPEGColorComponent)
File         : extracted/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
Lines (HEAD) : 431-434 (`colorConvertGrayscaleMCU`)

## Problem

```c
if (!((sx == 0) && (sy == 0))) {
    dx = dx / sx;          // crash if only sx==0 (or only sy==0)
    dy = dy / sy;
}
```

The condition fires only when **both** scale factors are zero. If
only one of them is zero, the corresponding divide hits SIGFPE.

## Fix

```diff
diff --git a/extracted/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c b/extracted/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
index 9db713516..f2e43ea19 100644
--- a/extracted/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
+++ b/extracted/plugins/JPEGReaderPlugin/src/common/JPEGReaderPlugin.c
@@ -428,10 +428,15 @@ primitiveColorConvertGrayscaleMCU(void)
 		dy = yComponent[CurrentYIndex];
 		sx = yComponent[HScaleIndex];
 		sy = yComponent[VScaleIndex];
-		if (!((sx == 0)
-			 && (sy == 0))) {
+		if (sx != 0 && sy != 0) {
 			dx = dx / sx;
 			dy = dy / sy;
+		} else if (sx != 0 || sy != 0) {
+			/* Only one of sx,sy is zero — malformed component.
+			 * The previous check only short-circuited when BOTH were
+			 * zero, so a partial-zero scale fell through to a
+			 * divide-by-zero on the other axis. */
+			return primitiveFail();
 		}
 		blockIndex = ((((usqInt) dy >> 3)) * (yComponent[BlockWidthIndex])) + (((usqInt) dx >> 3));
 		sampleIndex = (((usqInt) (dy & 7) << 3)) + (dx & 7);
```

## Test plan

- Decode JPEG with `HScaleIndex=0, VScaleIndex=2`. Before: SIGFPE
  on `dy / sy` (with `dy / 2` ok but `dx / 0` triggers). After:
  primitive fails cleanly.
- Normal JPEG: unchanged.

## Risk notes

- Strict bug fix; the original "both zero" branch is preserved.
- Pairs naturally with extended/2.4 which bounds the same indices
  for blockIndex; together they harden colorConvertGrayscaleMCU.
