¿Por qué el progtwig Linux que quita las frentes (char *) 0 no siempre es seguro?

Estoy probando un código que está diseñado para detectar cuándo un proceso secundario se ha segregado. Imagínese mi sorpresa cuando este código no siempre segfault:

#include  int main() { char *p = (char *)(unsigned long)0; putchar(*p); return 0; } 

Estoy corriendo bajo un kernel Debian Linux 2.6.26; mi shell es el AT&T ksh93 del paquete Debian ksh , versión M 93s + 2008-01-31. A veces, este progtwig no funciona, pero de lo contrario, simplemente termina de forma silenciosa con un estado de salida distinto de cero pero sin mensaje. Mi progtwig de detección de señales reporta lo siguiente:

 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 

Ejecutar bajo ksh puro muestra que el segfault también es raro:

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

Curiosamente, bash detecta correctamente el segfault cada vez .

Tengo dos preguntas:

  1. ¿Alguien puede explicar este comportamiento?

  2. ¿Alguien puede sugerir un progtwig de C simple que segregará de manera confiable en cada ejecución? También he intentado kill(getpid(), SIGSEGV) , pero obtengo resultados similares.


EDIT: jbcreix tiene la respuesta : mi detector Segfault se rompió. Me engañaron porque ksh tiene el mismo problema. Lo intenté con bash y bash hace bien cada vez.

Mi error fue que estaba pasando WNOHANG a waitpid() , donde debería haber pasado cero. ¡No sé qué podría haber estado pensando! Uno se pregunta cuál es el problema con ksh , pero esa es una pregunta aparte.

Al escribir en NULL se producirá un error de seguridad o un error en el bus.

A veces, un sistema operativo asignará una página de solo lectura a la dirección cero. Por lo tanto, a veces se puede leer desde NULL .

Aunque C define la dirección NULL como especial, la ‘implementación’ de ese estado especial en realidad es manejada por el subsistema de memoria virtual (VM) del sistema operativo.

WINE y dosemu deben asignar una página en NULL para la compatibilidad con Windows. Consulte mmap_min_addr en el kernel de Linux para reconstruir un kernel que no puede hacer esto.

mmap_min_addr es actualmente un tema candente debido a un exploit relacionado y una llama pública hacia Linus (de la fama de Linux, obviamente) de Theo de Raadt, del esfuerzo de OpenBSD.

Si está dispuesto a codificar al niño de esta manera, siempre puede llamar a: raise(SIGSEGV);

Además, puede obtener un puntero garantizado a segfault desde: int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);

Donde PROT_NONE es la clave para reservar memoria a la que no se puede acceder. Para Intel Linux de 32 bits, PAGE_SIZE es 4096.

No estoy seguro de por qué no tiene un comportamiento consistente. Pensaría que no es tan delicado con la lectura. O algo así, aunque probablemente estaría totalmente equivocado.

Intenta escribir en NULL. Esto parece ser consistente para mí. Aunque no tengo idea de por qué querrías usar esto. 🙂

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

La respuesta a la pregunta número dos de Wikipedia :

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