The overflow can "safely" overrun anything your program owns in memory. The only reason why the program should crash is if it tries to write to protected memory.
For example, if you use gets() on the stack:
Code:
char array[5];
char array2[5];
gets(array);
And enter a ten-character string, the rest will most likely end up in array2.
If you have it on the stack with nothing to catch it:
Code:
char array[5];
gets(array);
It will most likely end up overwriting the stack base pointer and return variable, as stack variables are stored backwards as an offset of the base pointer:
Code:
push %rbp /* pushes base to stack */
movl %rsp, %rbp /* base ptr = stack ptr */
movl $0, -0x4(%rbp) /* your array, offset by 4 (first four = return variable) */
/* if I wanted to access array[4] */
movl $0, -0x5(%rbp) /* stored backwards, series of five one-byte types */
/* so if gets() overwrites that, into array[6], for example.. */
movl $0, -0x3(%rbp) /* wut! this is modifying the return variable! */
/* now lets say it keeps going, and writes into array[9] */
movl $0, (%rbp) /* now, you just overwrote your base pointer */
You can see what happens if this continues.