The full sequence of events is:
- A user-space process executes a machine instruction that accesses a page of the address space that is either unmapped (there is no physical RAM there at all) or inaccessible in that fashion (write access to a read-only page, for instance).
- The CPU suspends execution of the offending process, and transfers control to the kernel with a memory protection exception.
- The kernel determines that this is due to an unrecoverable error and not, say, a page that needs to be retrieved from the swap space.
- The kernel sends the offending process a SIGSEGVsignal. The default behavior of this signal is to terminate a process that receives it. A program can override that by installing a handler for the signal, in which case something else rather more complicated would happen, but let's assume it has not done this.
- Therefore, the kernel terminates the offending process, which has all the same effects as calling _exit- open files are closed, memory is deallocated, etc.
- The kernel notifies the parent process, via another signal (SIGCHLD) and/or via one of thewaitfamily of system calls, that one of its children has exited. In your examples, the parent process is running a shell program, but it doesn't have to be: any process can create children and then wait for them to exit.
- The notification to the parent process includes information about how the process exited; in this case, that it was terminated due to a SIGSEGVsignal.
- The parent process may, if it wishes, report this information by printing a message. Shell programs almost always do this.
Your crsh doesn't include the code for step 8, but it happens anyway, because system runs /bin/sh "under the hood".  crsh is the grandparent in this scenario; the parent-process notification is fielded by /bin/sh, which prints its usual message.  Then /bin/sh itself exits, since it has nothing more to do, and the C library's implementation of system receives that exit notification.  You can see that exit notification in your code, by inspecting the return value of system; but it won't tell you that the grandchild process died on a segfault, because that was consumed by the intermediate shell process.
 
                