Auf x86-Systemen werden nicht viele Busfehler angezeigt. Ich habe untersucht, wann ein Busfehler (SIGBUS) auftritt. Ich habe x86 im Titel geschrieben, aber auch SPARC überprüft.
Busfehler (SIGBUS) ist, wie der Name schon sagt, ein Fehler, der auf einem Bus auftritt. Tritt auf, wenn ein Fehler auftritt, wenn die CPU eine Zugriffsanforderung an den physischen Speicher stellt (dies soll sein). Normalerweise ist für das Anwenderprogramm die logische Adresse sichtbar, und da die physikalische Adresse nicht direkt berührt wird, ist es für das Anwenderprogramm schwierig, einen Busfehler zu verursachen. Es ist auch bekannt, dass es aufgrund von Ausrichtungsfehlern auftritt. Dies ist jedoch bei x86 nicht der Fall, da die Ausrichtungsprüfung normalerweise deaktiviert ist. Soweit ich untersucht habe, wurde festgestellt, dass ein Busfehler auf zwei Arten verursacht werden kann: "Aufruf eines Systemaufrufs, der SIGBUS verursacht" und "Ausrichtungsfehler nach Aktivierung der Ausrichtungsprüfung".
Ein Beispiel in StackOverflow. SIGBUS wird angezeigt, wenn Sie den Bereich außerhalb des durch mmap gesicherten Bereichs berühren.
bus.c
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main() {
FILE *f = tmpfile();
int *m = (int*)mmap(0, 4, PROT_WRITE, MAP_PRIVATE, fileno(f), 0);
*m = 0;
return 0;
}
$ gcc bus.c
$ ./a.out
[1] 16871 bus error ./bus
Eine entsprechende Beschreibung finden Sie in man mmap.
The system shall always zero-fill any partial page at the end of an object. Further, the system shall never write out any modified portions of the last page of an object which are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.
Außerdem gibt die [Quelle] von mMap (http://lxr.free-electrons.com/source/mm/mmap.c#L3063) VM_FAULT_SIGBUS explizit zurück.
Ein Beispiel in hier, das durch char gesichert ist und auf das von int zugegriffen wird.
bus2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *p = (char*)malloc(sizeof(int) + 1);
memset(p, 0, sizeof(int) + 1);
p++;
printf("%d\n", *(int *)p);
return 0;
}
Dies endet normal trotz der Inkonsistenz der Ausrichtung. Dies liegt daran, dass das Flag x86 EFLAGS Alignment Check (AC) deaktiviert ist. Wenn dies aktiviert ist, tritt ein Busfehler auf.
bus2p.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
asm( "pushf\n\torl $0x40000,(%rsp)\n\tpopf");
char *p = (char*)malloc(sizeof(int) + 1);
memset(p, 0, sizeof(int) + 1);
p++;
printf("%d\n", *(int *)p);
return 0;
}
Selbst wenn das AC-Flag aktiviert ist, tritt der Busfehler unter Mac OS X nicht auf und endet normal.
Versuchen Sie, auf den Zeichenfolgenbereich zuzugreifen.
bus3.c
#include <stdio.h>
#include <stdlib.h>
int
main(void){
char *s = "test";
s[0] = '0';
printf("%s\n",s);
}
Dies ist ein Segmentierungsfehler (SIGSEGV) unter Linux, führt jedoch unter Mac zu einem Busfehler.
$ clang bus3.c
$ ./a.out
Bus error: 10
Zusammenfassend sieht es so aus. Ich habe auch die Ergebnisse von Cygwin aufgenommen. Ich hatte auch ein SPARC Linux-System, also habe ich es auch dort überprüft (ausgenommen bus2p.c, das Inline-Assembly verwendet).
bus.c | bus2.c | bus2p.c | bus3.c | |
---|---|---|---|---|
Linux | SIGBUS | Erfolgreiche Fertigstellung | SIGBUS | SIGSEGV |
Mac OS X | SIGBUS | Erfolgreiche Fertigstellung | Erfolgreiche Fertigstellung | SIGBUS |
Cygwin | SIGBUS | Erfolgreiche Fertigstellung | Erfolgreiche Fertigstellung | SIGSEGV |
SPARC | SIGSEGV | SIGBUS | ---- | SIGSEGV |
Im heutigen x86-System wird der Busfehler im Benutzerprogramm nur angezeigt, wenn Sie die Ausrichtungsprüfung explizit aktivieren, um einen inkonsistenten Ausrichtungszugriff durchzuführen oder einen Systemaufruf zu verwenden, der SIGBUS ausgibt. Die Ausnahme ist Mac, auf den hingewiesen wurde die Unterscheidung zwischen SIGBUS und SIGSEGV ist nicht eindeutig, und ein Busfehler tritt nur durch Zugriff auf die Zeichenfolge auf. Selbst unter demselben Linux ist das Verhalten bei SPARC ganz anders. Ich denke, es ist wahr, dass SIGBUS aufgrund einer falschen Ausrichtung ausgegeben wird, aber ich bin nicht sicher, warum es SIGSEGV aufgrund einer falschen mMap ausgegeben wird (Wird es nicht von POSIX entschieden?).
Ich mag es nicht, dass alle Systeme, die ich überprüft habe, unterschiedlich sind.
Recommended Posts