I'm testing code that is designed to detect when a child process has segfaulted. Imagine my surprised when this code does not always segfault:
#include <stdio.h>
int main() {
char *p = (char *)(unsigned long)0;
putchar(*p);
return 0;
}
I'm running under a Debian Linux 2.6.26 kernel; my shell is the AT&T ksh93
from the Debian ksh
package, Version M 93s+ 2008-01-31. Sometimes this program segfault but otherwise it simply terminates silently with a nonzero exit status but no message. My signal-detecting program reports the following:
segfault terminated by signal 11: Segmentation fault
segfault terminated by signal 53: Real-time signal 19
segfault terminated by signal 11: Segmentation fault
segfault terminated by signal 53: Real-time signal 19
segfault terminated by signal 53: Real-time signal 19
segfault terminated by signal 53: Real-time signal 19
segfault terminated by signal 53: Real-time signal 19
Running under pure ksh
shows that the segfault is also rare:
Running...
Running...
Running...
Running...
Running...
Running... Memory fault
Running...
Interestingly, bash
correctly detects the segfault every time.
I have two questions:
Can anyone explain this behavior?
Can anyone suggest a simple C program that will segfault reliably on every execution? I have also triedkill(getpid(), SIGSEGV)
, but I get similar results.
EDIT: jbcreix has the answer: my segfault detector was broken. I was fooled because ksh
has the same problem. I tried with bash
and bash
gets it right every time.
My error was that I was passing WNOHANG
to waitpid()
, where I should have been passing zero. I don't know what I could have been thinking! One wonders what is the matter with ksh
, but that's a separate question.
Overview. A segmentation fault (aka segfault) is a common condition that causes programs to crash; they are often associated with a file named core . Segfaults are caused by a program trying to read or write an illegal memory location.
The following are some typical causes of a segmentation fault: Attempting to access a nonexistent memory address (outside process's address space) Attempting to access memory the program does not have rights to (such as kernel structures in process context) Attempting to write read-only memory (such as code segment)
Writing to NULL
will reliably segfault or bus error.
Sometimes an OS will map a read-only page to the zero address. Thus, you can sometimes read from NULL
.
Although C defines the NULL
address as special, the 'implementation' of that special status is actually handled by the Operating System's Virtual Memory (VM) subsystem.
WINE and dosemu need to map a page at NULL
for Windows compatibility. See mmap_min_addr
in the Linux kernel to rebuild a kernel which cannot do this.
mmap_min_addr
is currently a hot topic due to a related exploit and a public flame toward Linus (of Linux fame, obviously) from Theo de Raadt, of the OpenBSD effort.
If you are willing to code the child this way, you could always call: raise(SIGSEGV);
Also, you can obtain a guaranteed-to-segfault pointer from:
int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);
Where PROT_NONE
is the key to reserving memory which cannot be accessed. For 32-bit Intel Linux, PAGE_SIZE is 4096.
I'm not sure why it doesn't have consistent behavior. I'd think that it's not as nit-picky with reading. Or something like that, though I'd probably be totally wrong.
Try writing at NULL. This seems to be consistent for me. I have no idea why you'd want to use this though. :)
int main()
{
*(int *)0 = 0xFFFFFFFF;
return -1;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With