Why is a Linux program that resolves (char *) 0 not always segfault?

I am testing code that is designed to detect when a child process has undergone undergoing. Imagine I'm surprised when this code is not always executed by sepfault:

#include <stdio.h> int main() { char *p = (char *)(unsigned long)0; putchar(*p); return 0; } 

I am working under the Debian Linux 2.6.26 kernel; my shell is AT & T ksh93 from the Debian ksh package, version M 93s + 2008-01-31. Sometimes this program is segfault, but otherwise it just ends silently with a non-zero exit status, but without a message. My signal detection 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 segfault is also rare:

 Running... Running... Running... Running... Running... Running... Memory fault Running... 

Interestingly, bash correctly defines segfault every time .

I have two questions:

  • Can anyone explain this behavior?

  • Can anyone suggest a simple C program that will execute segfault reliably with every run? I also tried kill(getpid(), SIGSEGV) , but I get similar results.


EDIT: jbcreix has the answer : my segfault detector was broken. I was tricked because ksh has the same problem. I tried with bash , and bash always fixed this.

My mistake was that I passed WNOHANG to waitpid() , where I had to pass zero. I do not know what I could think of! I wonder what happened to ksh , but this is a separate issue.

+6
c segmentation-fault linux waitpid
source share
3 answers

Writing to NULL will be reliably eliminated or a bus error.

Sometimes the OS displays a read-only page at a null address. This way you can sometimes read with NULL .

Although C defines a NULL address as special, the "implementation" of this special status is actually handled by the operating system virtual memory (VM) subsystem.

WINE and dosemu need to map the page to NULL for Windows compatibility. See mmap_min_addr in the Linux kernel for a kernel recovery that cannot do this.

mmap_min_addr is currently a hot topic due to the related exploit and public flames against Linus (from Linux fame, obviously) from Theo de Raadt from OpenBSD efforts.

If you want to encode a child this way, you can always call: raise(SIGSEGV);

In addition, you can get a pointer with a guarantee from segfault: int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);

Where PROT_NONE is the key to memory backup that cannot be accessed. For 32-bit Intel Linux, PAGE_SIZE is 4096.

+12
source share

I'm not sure why he does not have consistent behavior. I would think that this is not like a jerk with reading. Or something like that, although I'm probably mistaken.

Try writing in NULL. It seems consistent to me. I have no idea why you want to use this. :)

 int main() { *(int *)0 = 0xFFFFFFFF; return -1; } 
+1
source share

Answer to question number two from Wikipedia :

  int main(void) { char *s = "hello world"; *s = 'H'; } 
+1
source share

All Articles