Was bedeutet die Meldung "Busfehler" und wie unterscheidet sie sich von einem Segfault?
Was bedeutet die Meldung "Busfehler" und wie unterscheidet sie sich von einem Segfault?
Antworten:
Busfehler sind heutzutage auf x86 selten und treten auf, wenn Ihr Prozessor nicht einmal den angeforderten Speicherzugriff versuchen kann, normalerweise:
Segmentierungsfehler treten beim Zugriff auf Speicher auf, der nicht zu Ihrem Prozess gehört. Sie sind sehr häufig und resultieren normalerweise aus:
PS: Genauer gesagt manipuliert dies nicht den Zeiger selbst, der Probleme verursacht, sondern greift auf den Speicher zu, auf den es zeigt (Dereferenzierung).
/var/cache
einfach voll askubuntu.com/a/915520/493379
static_cast
einen void *
Parameter für ein Objekt festgelegt, in dem ein Rückruf gespeichert ist (ein Attribut zeigt auf das Objekt und das andere auf die Methode). Dann wird der Rückruf aufgerufen. Was jedoch als void *
etwas völlig anderes übergeben wurde, verursachte der Methodenaufruf den Busfehler.
Ein Segfault greift auf Speicher zu, auf den Sie nicht zugreifen dürfen. Es ist schreibgeschützt, Sie haben keine Erlaubnis usw.
Ein Busfehler versucht, auf Speicher zuzugreifen, der möglicherweise nicht vorhanden sein kann. Sie haben eine Adresse verwendet, die für das System bedeutungslos ist, oder die falsche Art von Adresse für diesen Vorgang.
mmap
minimales POSIX 7 Beispiel
"Busfehler" tritt auf, wenn der Kernel SIGBUS
an einen Prozess sendet .
Ein minimales Beispiel, das es produziert, weil ftruncate
es vergessen wurde:
#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */
int main() {
int fd;
int *map;
int size = sizeof(int);
char *name = "/a";
shm_unlink(name);
fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
/* THIS is the cause of the problem. */
/*ftruncate(fd, size);*/
map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
/* This is what generates the SIGBUS. */
*map = 0;
}
Laufen Sie mit:
gcc -std=c99 main.c -lrt
./a.out
Getestet in Ubuntu 14.04.
POSIX beschreibt SIGBUS
als:
Zugriff auf einen undefinierten Teil eines Speicherobjekts.
Die mmap-Spezifikation besagt Folgendes :
Verweise innerhalb des Adressbereichs, die bei pa beginnen und für len Bytes bis zu ganzen Seiten nach dem Ende eines Objekts fortgesetzt werden, führen zur Lieferung eines SIGBUS-Signals.
Und shm_open
sagt, dass es Objekte der Größe 0 generiert:
Das gemeinsam genutzte Speicherobjekt hat eine Größe von Null.
Also bei *map = 0
uns über das Ende des zugeordneten Objekt berühren.
Nicht ausgerichtete Stapelspeicherzugriffe in ARMv8 aarch64
Dies wurde erwähnt unter: Was ist ein Busfehler? für SPARC, aber hier werde ich ein reproduzierbareres Beispiel geben.
Sie benötigen lediglich ein freistehendes aarch64-Programm:
.global _start
_start:
asm_main_after_prologue:
/* misalign the stack out of 16-bit boundary */
add sp, sp, #-4
/* access the stack */
ldr w0, [sp]
/* exit syscall in case SIGBUS does not happen */
mov x0, 0
mov x8, 93
svc 0
Dieses Programm löst dann SIGBUS unter Ubuntu 18.04 aarch64, Linux-Kernel 4.15.0 auf einem ThunderX2-Server aus .
Leider kann ich es im QEMU v4.0.0-Benutzermodus nicht reproduzieren. Ich bin mir nicht sicher, warum.
Der Fehler scheint durch die optionale und gesteuert zu werden SCTLR_ELx.SA
und SCTLR_EL1.SA0
Felder, ich habe die damit verbundenen Dokumente zusammengefasst ein bisschen weiter hier .
Ich glaube, der Kernel löst SIGBUS aus, wenn eine Anwendung eine Datenfehlausrichtung auf dem Datenbus aufweist. Ich denke, da die meisten [?] Modernen Compiler für die meisten Prozessoren die Daten für die Programmierer auffüllen / ausrichten, werden die Ausrichtungsprobleme von früher (zumindest) gemildert, und daher sieht man SIGBUS heutzutage nicht allzu oft (AFAIK).
Von: Hier
Sie können SIGBUS auch erhalten, wenn eine Codepage aus irgendeinem Grund nicht ausgelagert werden kann.
mmap
eine Datei größer als die Größe von/dev/shm
Ein spezielles Beispiel für einen Busfehler, den ich gerade beim Programmieren von C unter OS X festgestellt habe:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
Falls Sie sich nicht erinnern, strcat
hängen die Dokumente das zweite Argument an das erste an, indem Sie das erste Argument ändern (drehen Sie die Argumente um und es funktioniert einwandfrei). Unter Linux gibt dies (wie erwartet) einen Segmentierungsfehler, unter OS X jedoch einen Busfehler. Warum? Ich weiß es wirklich nicht.
"foo"
wird in einem schreibgeschützten Speichersegment gespeichert, so dass es unmöglich ist, darauf zu schreiben. Es wäre kein Stapelüberlaufschutz, sondern nur ein Speicherschreibschutz (dies ist eine Sicherheitslücke, wenn Ihr Programm sich selbst neu schreiben kann).
Eine klassische Instanz eines Busfehlers tritt bei bestimmten Architekturen auf, z. B. beim SPARC (zumindest bei einigen SPARCs, möglicherweise wurde dies geändert), wenn Sie einen falsch ausgerichteten Zugriff ausführen. Zum Beispiel:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Dieses Snippet versucht, den 32-Bit-Integer-Wert 0xdeadf00d
in eine Adresse zu schreiben, die (höchstwahrscheinlich) nicht richtig ausgerichtet ist, und erzeugt einen Busfehler bei Architekturen, die in dieser Hinsicht "wählerisch" sind. Der Intel x86 ist übrigens keine solche Architektur, er würde den Zugriff ermöglichen (wenn auch langsamer ausführen).
Dies hängt von Ihrem Betriebssystem, Ihrer CPU, Ihrem Compiler und möglicherweise anderen Faktoren ab.
Im Allgemeinen bedeutet dies, dass der CPU-Bus einen Befehl nicht ausführen oder einen Konflikt erleiden konnte. Dies kann jedoch je nach Umgebung und ausgeführtem Code eine ganze Reihe von Dingen bedeuten.
-Adam
Dies bedeutet normalerweise einen nicht ausgerichteten Zugriff.
Ein Versuch, auf Speicher zuzugreifen, der physisch nicht vorhanden ist, würde ebenfalls zu einem Busfehler führen. Dies wird jedoch nicht angezeigt, wenn Sie einen Prozessor mit einer MMU und einem Betriebssystem verwenden, das nicht fehlerhaft ist, da Sie keinen Fehler haben - Vorhandener Speicher, der dem Adressraum Ihres Prozesses zugeordnet ist.
scanf
). Bedeutet das, dass OS X Mavericks fehlerhaft ist? Wie wäre das Verhalten auf einem nicht fehlerhaften Betriebssystem gewesen?
Mein Grund für einen Busfehler unter Mac OS X war, dass ich versucht habe, ungefähr 1 MB auf dem Stapel zuzuweisen. Dies funktionierte in einem Thread gut, aber bei Verwendung von openMP führt dies zu Busfehlern, da Mac OS X eine sehr begrenzte Stapelgröße für Nicht-Haupt-Threads hat .
Ich stimme allen obigen Antworten zu. Hier sind meine 2 Cent bezüglich des BUS-Fehlers:
Ein BUS-Fehler muss nicht aus den Anweisungen im Programmcode hervorgehen. Dies kann passieren, wenn Sie eine Binärdatei ausführen und während der Ausführung die Binärdatei geändert wird (durch einen Build überschrieben oder gelöscht usw.).
Überprüfen, ob dies der Fall ist:
Eine einfache Möglichkeit, zu überprüfen, ob dies die Ursache ist, besteht darin, laufende Instanzen derselben Binärdatei zu starten und einen Build auszuführen. Beide laufenden Instanzen würden SIGBUS
kurz nach Abschluss des Builds mit einem Fehler abstürzen und die Binärdatei ersetzen (diejenige, die beide Instanzen derzeit ausführen).
Grund: Dies liegt daran, dass das Betriebssystem Speicherseiten austauscht und in einigen Fällen die Binärdatei möglicherweise nicht vollständig im Speicher geladen ist. Diese Abstürze treten auf, wenn das Betriebssystem versucht, die nächste Seite aus derselben Binärdatei abzurufen, die Binärdatei sich jedoch seit ihrer letzten Änderung geändert hat Lies es.
Um die oben beantwortete Antwort von blxtd zu ergänzen, treten auch Busfehler auf, wenn Ihr Prozess nicht versuchen kann, auf den Speicher einer bestimmten 'Variablen' zuzugreifen .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Beachten Sie die " versehentliche " Verwendung der Variablen "i" in der ersten "for-Schleife"? Das ist es, was in diesem Fall den Busfehler verursacht.
Ich habe gerade herausgefunden, wie schwierig es ist, auf einem ARMv7-Prozessor Code zu schreiben, der bei Nichtoptimierung einen Segmentierungsfehler verursacht, beim Kompilieren mit -O2 jedoch einen Busfehler (mehr optimieren).
Ich benutze den GCC ARM gnueabihf Cross Compiler von Ubuntu 64 Bit.
Ein typischer Pufferüberlauf, der zu einem Busfehler führt, ist:
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Wenn hier die Größe der Zeichenfolge in doppelten Anführungszeichen ("") größer als die Puffergröße ist, wird ein Busfehler ausgegeben.