# Extended 3.7 — B2DPlugin primitiveCopyBuffer: GWBufferTop unchecked

Bug ref      : pharo.md §3.7
Severity     : HIGH (write past dst when workBuffer is malformed)
File         : extracted/plugins/B2DPlugin/src/common/B2DPlugin.c
Lines (HEAD) : 10770-10781

## Problem

```c
diff = (slotSizeOf(buf2)) - (slotSizeOf(buf1));
if (diff < 0) return primitiveFailFor(GEFSizeMismatch);
...
for (i = 0; i < (workBuffer[GWBufferTop]); i += 1) { dst[i] = src[i]; }
```

`loadWorkBufferFrom` validates `GWSize` against `slotSizeOf(buf1)`
but does NOT validate `GWBufferTop`. A workBuffer where
`GWBufferTop > GWSize` (and therefore > slotSizeOf(buf1)) drives
the copy loop past `dst`.

## Fix

Validate `GWBufferTop ≤ slotSizeOf(buf1) ≤ slotSizeOf(buf2)` before
the loop.

```diff
--- a/extracted/plugins/B2DPlugin/src/common/B2DPlugin.c
+++ b/extracted/plugins/B2DPlugin/src/common/B2DPlugin.c
@@ -10766,8 +10766,13 @@ primitiveCopyBuffer(void)
 	diff = (slotSizeOf(buf2)) - (slotSizeOf(buf1));
 	if (diff < 0) {
 		return primitiveFailFor(GEFSizeMismatch);
 	}
+	if (workBuffer[GWBufferTop] < 0 ||
+	    (sqInt)workBuffer[GWBufferTop] > (sqInt)slotSizeOf(buf1) ||
+	    (sqInt)workBuffer[GWSize]      > (sqInt)slotSizeOf(buf2)) {
+		return primitiveFailFor(GEFSizeMismatch);
+	}
 	src = workBuffer;
 	dst = firstIndexableField(buf2);
 	for (i = 0; i < (workBuffer[GWBufferTop]); i += 1) {
 		dst[i] = (src[i]);
 	}
```

## Test plan

- Construct a workBuffer whose GWBufferTop is one larger than
  GWSize; call primitiveCopyBuffer. Before: ASAN reports OOB write
  to `dst`. After: primitive fails cleanly.
- Legitimate workBuffer: unchanged behaviour.

## Risk notes

- Pure pre-loop validation; success path unchanged.
- Same defensive pattern as `loadWorkBufferFrom` already uses for
  GWSize.
