The ANSI Smalltalk standard is characteristically vague here.
Both the memmove and memcpy readings are consistent with it.
The standard is characteristically buggy here too: the two
lines I've flagged with ** disagree.�� I take the second one
to be correct.

5.7.12.5 Message:

�� replaceFrom: start to: stop with: replacementElements startingAt: replacementStart

Synopsis

�� Replace the elements of the receiver between positions start and stop inclusive
�� with the elements of replacementElements, in their original order, starting at
�� position replacementStart.�� Answer the receiver.

Definition: "for" <sequencedCollection>

�� The element at position replacementStart in replacementElements is stored
�� in the receiver at position start; the element at replacementStart + 1 is
�� stored at position start + 1; etc.
�� Any previously stored elements at these positions in the receiver are replaced.
**If the size of replacementElements is not equal to (replacementStart+stop-start),
�� the result of sending this message is unspecified.

Errors,

�� If start < 1 or start > the receiver���s size.
�� If stop < 1 or stop > the receiver���s size.
�� If replacementStart < 1 or replacementStart > replacementElements size.
**If replacementElements size - replacementStart + 1 < stop - start + 1.

For what it's worth, GNU Smalltalk answers #(1 2 3 1 2 3 4 8), as does my
Smalltalk library.�� So does VisualWorks.�� It's a primitive in VW, so I
can't see what the code does, but the comment is tolerably clear:
"No range checks are performed, but�� overlapping replacements are handled correctly."
VisualAge Smalltalk gives the memmove answer too.�� The Dolphin sources say
"Overlapping moves are correctly handled."�� ST/X makes a special check for the
receiver and source being the same object and conditionally calls memmove to
do the transfer.�� Strongtalk doesn't check for receiver == source but does
check for repStart < start, so also belongs to the memmove group.

So Squeak/Pharo stand out as different here.
susie-0.3 and syx-0.1.7 and panda all do the memcpy() thing too,
but they don't count as finished.

On Fri, 9 Aug 2019 at 05:31, James Foster <Smalltalk@jgfoster.net> wrote:
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/). ��

While it isn���t the implementation I would choose, at least now I know!

James Foster