Warum ist Linux-Programm, dass derefrences (char *) 0 nicht immer segfault?
-
20-09-2019 - |
Frage
Ich teste Code, der ausgelegt ist, zu erkennen, wenn ein Kind Prozess segfaulted hat. Stellen Sie sich meine überrascht, wenn dieser Code nicht immer segfault:
#include <stdio.h>
int main() {
char *p = (char *)(unsigned long)0;
putchar(*p);
return 0;
}
Ich laufe unter Debian Linux 2.6.26-Kernel; meine Schale ist die AT & T ksh93
vom Debian ksh
Paket, Version M 93s + 2008-01-31. Manchmal dieses Programm segfault aber ansonsten einfach es endet leise mit einem von Null verschiedenen Exit-Status, aber keine Nachricht. Mein signaldetektierenden Programm meldet die folgende:
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
Beim Laufen unter reinem ksh
zeigt, dass die segfault ist auch selten:
Running...
Running...
Running...
Running...
Running...
Running... Memory fault
Running...
Interessanterweise bash
richtig erkennt die segfault jedes Mal, .
Ich habe zwei Fragen:
-
Kann jemand dieses Verhalten erklären?
-
Kann jemand empfehlen, ein einfaches C-Programm, das zuverlässig bei jeder Ausführung segfault wird? Ich habe auch tried
kill(getpid(), SIGSEGV)
, aber ich habe ähnliche Ergebnisse.
EDIT: jbcreix hat die Antwort : mein segfault Detektor defekt war. Ich wurde getäuscht, weil ksh
hat das gleiche Problem. Ich habe versucht, mit bash
und bash
macht es richtig jedes Mal.
Mein Fehler war, dass ich WNOHANG
zu waitpid()
vorging, wo ich Null vorbei sein sollte. Ich weiß nicht, was ich habe gedacht könnte! Man fragt sich, was mit ksh
ist, aber das ist eine andere Frage.
Lösung
Schreiben zu NULL
zuverlässig segfault oder Bus-Fehler.
Manchmal wird ein O eine Nur-Lese-Seite auf die Null-Adresse zuordnen. So können Sie manchmal von NULL
lesen.
Auch wenn C die NULL
Adresse als Sonder definiert, die ‚Umsetzung‘ dieser besonderen Status wird durch das Betriebssystem des virtuellen Speichers tatsächlich behandelt (VM) Subsystem.
WEIN und dosemu Notwendigkeit, eine Seite auf NULL
für Windows-Kompatibilität kartieren. Siehe mmap_min_addr
im Linux-Kernel einen Kernel neu zu erstellen, die dies nicht tun.
mmap_min_addr
ist derzeit ein heißes Thema aufgrund eines im Zusammenhang auszunutzen und eine öffentliche Flamme auf Linus (von Linux Ruhm, natürlich) von Theo de Raadt, des OpenBSD Aufwand.
Wenn Sie das Kind auf diese Weise bereit, um Code sind, können Sie jederzeit anrufen: raise(SIGSEGV);
Sie können aber auch einen Zeiger garantiert zu segfault erhalten von:
int *ptr_segv = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);
Wo PROT_NONE
ist der Schlüssel Speicher zu reservieren, die nicht zugegriffen werden kann. Für 32-Bit-Intel-Linux, PAGE_SIZE 4096.
Andere Tipps
Ich bin nicht sicher, warum es nicht ein konsistentes Verhalten hat. Ich würde denken, dass es mit dem Lesen nicht als nit-wählerisch ist. Oder so ähnlich, obwohl ich würde wahrscheinlich völlig falsch sein.
Versuchen Sie, bei NULL schreiben. Dies scheint für mich, konsequent zu sein. Ich habe keine Ahnung, warum Sie wollen würde dies aber verwenden. :)
int main()
{
*(int *)0 = 0xFFFFFFFF;
return -1;
}
Die Antwort auf Frage Nummer zwei von Wikipedia :
int main(void)
{
char *s = "hello world";
*s = 'H';
}