# Extended 3.9 — src/externalPrimitives.c: strcpy of caller-controlled lookupName

Bug ref      : pharo.md §3.9
Severity     : HIGH (stack overflow on every plugin load with name > 256 bytes)
File         : src/externalPrimitives.c
Lines (HEAD) : 126-138 (`ioFindExternalFunctionInAccessorDepthInto`)

## Problem

```c
char buf[256];
...
#ifdef _WIN32
    strcpy_s(buf, 256, lookupName);          // truncates on Windows
#else
    strcpy(buf, lookupName);                 // unbounded on Unix/macOS
#endif
snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf), "AccessorDepth");
```

On Unix/macOS, an image whose primitive name exceeds 255 bytes
overflows `buf` on every plugin load. Stack overflow with
attacker-controlled (image-controlled) content.

## Fix

Use `snprintf` to compose the whole string in one bounded call.

```diff
diff --git a/src/externalPrimitives.c b/src/externalPrimitives.c
index 3fd40549f..0fa5ceab7 100644
--- a/src/externalPrimitives.c
+++ b/src/externalPrimitives.c
@@ -125,17 +125,17 @@ ioFindExternalFunctionInAccessorDepthInto(char *lookupName, void *moduleHandle,
     {
         char buf[256];
         signed char *accessorDepthVarPtr;
-
-#ifdef _WIN32
-        /*
-        * Unsafe version of deprecated strcpy for compatibility
-        * - does not check error code
-        */
-        strcpy_s(buf, 256, lookupName);
-#else
-        strcpy(buf, lookupName);
-#endif
-    	snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf), "AccessorDepth");
+        int _len;
+
+        /* Use snprintf so the AccessorDepth probe is bounded. The
+         * previous Unix branch used unbounded strcpy and overflowed
+         * `buf` on any primitive whose name exceeded 255 bytes. */
+        _len = snprintf(buf, sizeof(buf), "%sAccessorDepth", lookupName);
+        if (_len < 0 || (size_t)_len >= sizeof(buf)) {
+            /* Name too long for the AccessorDepth probe; treat as not present. */
+            *accessorDepthPtr = -1;
+            return function;
+        }
     	accessorDepthVarPtr = (signed char *)getModuleSymbol(moduleHandle, buf);
     	/* The Slang machinery assumes accessor depth defaults to -1, which
     	 * means "no accessor depth".  It saves space not outputting -1 depths.
```

## Test plan

- Provide a primitive whose lookupName is 300 bytes. Before: stack
  overflow on Unix; truncated probe on Windows. After: clean
  "no accessor depth" fallback.
- Normal lookup (short name): unchanged behaviour.

## Risk notes

- The accessor-depth probe is best-effort; a too-long name now
  cleanly reports "no accessor depth" rather than corrupting the
  stack.
- `snprintf` is portable C99; both branches now share the same path.
