[LINUX] Verursacht einen Busfehler auf x86

Einführung

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.

Über Busfehler

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".

Verwenden Sie mmap

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.

Beispiele für Ausrichtungsinkonsistenzen

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.

Nicht autorisierter Zugriff auf den Zeichenfolgenbereich

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

Zusammenfassung

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

Verursacht einen Busfehler auf x86
Erstellen Sie eine Python-Entwicklungsumgebung unter Mac OS X.
Erstellen Sie eine Python-Entwicklungsumgebung mit OS X Lion
Windows10 (x64) Erstellen Sie nativ eine maschinelle Lernumgebung
Ein Kommentar zum Boruta-Algorithmus
Setzen Sie Python 3.x in Ubuntu ein
Führen Sie Tensorflow 2.x unter Python 3.7 aus
Erstellen Sie ein Klassenzimmer auf Jupyterhub
Hinweise zur Vorbereitung der Python-Entwicklungsumgebung unter Mac OS X.