Abortar em vez de segfault com violação de memória clara

Eu me deparei com esse comportamento estranho quando se lida com cordas C. Este é um exercício do livro K & R onde eu deveria escrever uma função que acrescenta uma string ao final de outra string. Isso obviamente requer que a string de destino tenha memória suficiente alocada para que a string de origem se ajuste. Aqui está o código:

 /* strcat: Copies contents of source at the end of dest */
 char *strcat(char *dest, const char* source) {
  char *d = dest;
  // Move to the end of dest
  while (*dest != '\0') {
    dest++;
  } // *dest is now '\0'

  while (*source != '\0') {
    *dest++ = *source++;
  }
  *dest = '\0';
  return d;
}

Durante o teste, escrevi o seguinte, esperando que um segfault acontecesse enquanto o programa estava em execução:

int main() {
  char s1[] = "hello";
  char s2[] = "eheheheheheh"; 
  printf("%s\n", strcat(s1, s2));
}

Tanto quanto eu entendo s1 recebe uma matriz de 6chars alocado e s2 uma matriz de 13chars. Eu pensei que quandostrcat tenta gravar em s1 em índices maiores que 6 o programa se separaria. Em vez disso tudo funciona bem, mas o programa não sai de forma limpa, em vez disso:

helloeheheheheheh
zsh: abort      ./a.out

e sai com o código 134, o que eu acho que significa abortar.

Por que não estou obtendo um segfault (ou sobrescrevendo o s2 se as strings estão alocadas na pilha)? Onde estão essas seqüências de caracteres na memória (a pilha ou o heap)?

Obrigado pela ajuda.

questionAnswers(6)

yourAnswerToTheQuestion