# Extended 3.4 — MiscPrimitivePlugin primitiveCompressToByteArray: signed-overflow defeats size check

Bug ref      : pharo.md §3.4
Severity     : HIGH (heap overwrite via size > 2^29 on 32-bit builds)
File         : extracted/plugins/MiscPrimitivePlugin/src/common/MiscPrimitivePlugin.c
Lines (HEAD) : 195-215

## Problem

```c
size = sizeOfSTArrayFromCPrimitive(bm);
destSize = sizeOfSTArrayFromCPrimitive(ba);
if (destSize < (((size * 4) + 7) + ((size / 0x7C0) * 3))) {
    return primitiveFailFor(PrimErrUnsupported);
}
```

`size * 4` is a signed `sqInt` multiply. On 32-bit `sqInt`, `size`
≥ 2^29 wraps the product to a small value; `destSize` (also bounded
by image size) is larger than the wrapped expression, so the check
passes. The subsequent compression loop writes through `ba` based
on the unwrapped expectation.

Separately, `bm` is read as `int[]` later but has no
`isWords||isBitmap` check.

## Fix

Use unsigned 64-bit arithmetic for the size requirement; check `bm`
format.

```diff
diff --git a/plugins/MiscPrimitivePlugin/src/common/MiscPrimitivePlugin.c b/plugins/MiscPrimitivePlugin/src/common/MiscPrimitivePlugin.c
index 0eb51e8a8..8c471edde 100644
--- a/plugins/MiscPrimitivePlugin/src/common/MiscPrimitivePlugin.c
+++ b/plugins/MiscPrimitivePlugin/src/common/MiscPrimitivePlugin.c
@@ -210,8 +210,15 @@ primitiveCompressToByteArray(void)
 	ba = firstIndexableField(stackValue(0));
 	size = sizeOfSTArrayFromCPrimitive(bm);
 	destSize = sizeOfSTArrayFromCPrimitive(ba);
-	if (destSize < (((size * 4) + 7) + ((size / 0x7C0) * 3))) {
-		return primitiveFailFor(PrimErrUnsupported);
+	{
+		/* Use uint64 to avoid signed overflow on the size requirement;
+		 * a wrapped (size*4)+7+... would let the check pass for huge sizes
+		 * and the compression loop would then write past ba. */
+		uint64_t required = ((uint64_t)size * 4) + 7
+		                  + ((uint64_t)size / 0x7C0) * 3;
+		if ((uint64_t)destSize < required) {
+			return primitiveFailFor(PrimErrUnsupported);
+		}
 	}
 	/* begin encodeInt:in:at: */
 	if (size <= 223) {

```

## Test plan

- 32-bit build: supply `bm` of size `0x40000000`; before, the size
  check wraps and the compression loop writes past `ba`. After, the
  primitive fails cleanly.
- Normal-sized inputs: unchanged behaviour.

## Risk notes

- 64-bit builds were always safe; this is mainly a 32-bit hardening.
- Same `isWords||isBitmap` check pattern as 3.3.
