Je teste le code conçu pour détecter le moment où un processus enfant est en échec. Imaginez ma surprise quand ce code ne se sépare pas toujours:
#include int main() { char *p = (char *)(unsigned long)0; putchar(*p); return 0; }
Je cours sous un kernel Debian Linux 2.6.26; mon shell est le AT & T ksh93
du paquet Debian ksh
, version M 93s + 2008-01-31. Parfois, ce programme se sépare mais il se termine simplement en mode silencieux avec un statut de sortie différent de zéro mais pas de message. Mon programme de détection de signal rapporte ce qui suit:
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
Courir sous ksh
pur montre que le segfault est également rare:
Running... Running... Running... Running... Running... Running... Memory fault Running...
Fait intéressant, bash
détecte correctement le segfault à chaque fois .
J’ai deux questions:
Quelqu’un peut-il expliquer ce comportement?
Quelqu’un peut-il suggérer un programme en C simple qui bloquera de manière fiable chaque exécution? J’ai aussi essayé de kill(getpid(), SIGSEGV)
, mais j’obtiens des résultats similaires.
EDIT: jbcreix a la réponse : mon détecteur de segfault était cassé. J’ai été dupe parce que ksh
a le même problème. J’ai essayé avec bash
et bash
fait bien chaque fois.
Mon erreur était que je passais WNOHANG
à waitpid()
, où j’aurais dû passer zéro. Je ne sais pas ce que j’aurais pu penser! On se demande quel est le problème avec ksh
, mais c’est une question distincte.
Si vous NULL
à NULL
, une erreur de segmentation ou une erreur de bus se produit.
Parfois, un système d’exploitation mappe une page en lecture seule sur l’adresse zéro. Ainsi, vous pouvez parfois lire à partir de NULL
.
Bien que C définisse l’adresse NULL
comme spéciale, l’implémentation de ce statut spécial est en fait gérée par le sous-système Virtual Memory (VM) du système d’exploitation.
WINE et dosemu doivent mapper une page à la compatibilité NULL
pour Windows. Voir mmap_min_addr
dans le kernel Linux pour reconstruire un kernel qui ne peut pas faire cela.
mmap_min_addr
est actuellement un sujet d’actualité en raison d’un exploit apparent et d’une flamme publique envers Linus (de la renommée Linux, évidemment) de Theo de Raadt, de l’effort OpenBSD.
Si vous souhaitez coder l’enfant de cette façon, vous pouvez toujours appeler: raise(SIGSEGV);
En outre, vous pouvez obtenir un pointeur garanti à segfault à partir de: int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);
Où PROT_NONE
est la clé pour réserver de la mémoire PROT_NONE
. Pour Intel Linux 32 bits, PAGE_SIZE est 4096.
Je ne sais pas pourquoi il n’a pas un comportement cohérent. Je pense que ce n’est pas aussi difficile à lire. Ou quelque chose comme ça, bien que je sois probablement complètement faux.
Essayez d’écrire à NULL. Cela semble être cohérent pour moi. Je n’ai aucune idée de la raison pour laquelle vous voulez l’utiliser. 🙂
int main() { *(int *)0 = 0xFFFFFFFF; return -1; }
La réponse à la question numéro deux de Wikipedia :
int main(void) { char *s = "hello world"; *s = 'H'; }