After many hours of debugging I’ve finally discovered that Pharo’s implementation of #replaceFrom:to:with:startingAt: does not make any check for overlapping regions to avoid destructive operations.
| bytes | bytes := #(1 2 3 4 5 6 7 8) copy. bytes replaceFrom: 4 to: 7 with: bytes startingAt: 1. bytes "#(1 2 3 1 2 3 1 8) in Pharo" "#(1 2 3 1 2 3 4 8) in GemStone” Essentially, Pharo has taken a memcpy() approach rather than a memmove() approach (https://fresh2refresh.com/c-programming/c-interview-questions-answers/what-is-the-difference-between-memcpy-ampersand-memmove-functions-in-c/ <https://fresh2refresh.com/c-programming/c-interview-questions-answers/what-is-the-difference-between-memcpy-ampersand-memmove-functions-in-c/>). While it isn’t the implementation I would choose, at least now I know! James Foster