W funkcji masz podany wskaźniki i wielkość bloku. Każdy ze wskaźników ma modyfikator restrict. To oznacza że nigdy nie dojdzie do sytuacji by na miejsce w pamięci na które wskazuje wskaźnik, wskazywał inny wskaźnik aktywny w tej funkcji. W przeciwnym wypadku będzie UB (zachowanie niezdefiniowane). Niezdefiniowane - oznacza że może się nic nie stać, może program "się wywrócić", może dojść do zniszczenia danych na dysku... cokolwiek....
Teraz pomyśl o tym że standard dopuszcza w strcpy() kopiowanie "od przodu" (czyli od najmniejszych adresów) lub "od tyłu" (czyli od największych adresów. Wybór zależy od specyfiki platformy lub twórców kompilatora. Ogólnie wybierają to co będzie szybsze na danej platformie. Co się stanie w takim przypadku gdy będzie zachowana taka wolność wyboru? Dane zostaną skopiowane poprawnie? Rozważ obydwa przypadki a zobaczysz jakie są niebezpieczeństwa.
Jeśli nie masz pewności że dane się nie nakładają/zazębiają/wskazują na to samo miejsce, stosuj memmove().