First of all C language have not boundary check. In effect it have no check at all on almost everything. This is the joy and the doom of C.
Now going back to the issue, if you overflow the memory doesn't mean that you trigger a segfault.
Lets have a closer look to how it works.
When you start a program, or enter a subroutine the processor saves on the stack the address to which return when function ends.
The stack has been initialized from OS during process memory allocation, and got a range of legal memory where you can read or write as you like, not only store return addresses.
The common practice used by compilers to create local (automatic) variables is to reserve some space on the stack, and use that space for variables. Look following well known 32 bits assembler sequence, named prologue, that you'll find on any function enter:
push ebp ;save register on the stack
mov ebp,esp ;get actual stack address
sub esp,4 ;displace the stack of 4 bytes that will be used to store a 4 chars array
considering that stack grows in the reverse direction of data, the layout of memory is:
0x0.....1C [Parameters (if any)] ;former function
0x0.....18 [Return Address]
0x0.....14 EBP
0x0.....10 0x0......x ;Local DWORD parameter
0x0.....0C [Parameters (if any)] ;our function
0x0.....08 [Return Address]
0x0.....04 EBP
0x0.....00 0, 'c', 'b', 'a' ;our string of 3 chars plus final nul
This is known as stack frame.
Now consider the string of four bytes starting at 0x0....0 and ending at 0x....3. If we write more than 3 chars in the array we will go replacing sequentially: the saved copy of EBP, the return address, parameters, local variables of previous function then its EBP, return address, etc.
The most scenographic effect we get is that, on function return, the CPU try to jump back to a wrong address generating a segfault. Same behaviour can be achieved if one of local variables are pointers, in this case we will try to read, or write, to wrong locations triggering again the segfault.
When segfault could not happen:
when the bloated variable is not on the stack, or you have so many local variables that you overwrite them without touching the return address (and they are not pointers).
Another case is that the processor reserves a guard space between local variables and return address, in this case the buffer overflow doesn't reach the address.
Another possibility is accessing array elements randomly, in this case an oversized array can exceed stack space and overflow on other data, but luckily we mdon't touch those elements that are mapped where is saved the return address (everythibng can happen...).
When we can have segfault bloating variables that are not on stack?
When overflowing array bound or pointers.
I hope these are useful info...