Que signifie le message "erreur de bus" et en quoi diffère-t-il d'une erreur de segmentation?
Les erreurs de bus sont rares de nos jours sur x86 et surviennent lorsque votre processeur ne peut même pas tenter d'accéder à la mémoire demandée, généralement:
Les erreurs de segmentation se produisent lors de l'accès à une mémoire n'appartenant pas à votre processus. Elles sont très courantes et résultent généralement de:
PS: Pour être plus précis, il ne s'agit pas d'une manipulation du pointeur lui-même, mais d'un accès à la mémoire sur laquelle il pointe (déréférencement).
Un segfault accède à de la mémoire à laquelle vous n'êtes pas autorisé. C'est en lecture seule, vous n'avez pas la permission, etc ...
Une erreur de bus tente d’accéder à une mémoire impossible. Vous avez utilisé une adresse qui n'a pas de sens pour le système ou un type d'adresse incorrect pour cette opération.
Je pense que le noyau déclenche SIGBUS lorsqu'une application présente un défaut d'alignement des données sur le bus de données. Je pense que puisque la plupart des compilateurs modernes pour la plupart des processeurs compilent/alignent les données pour les programmeurs, les problèmes d’alignement de jadis (au moins) sont mitigés et, par conséquent, on ne voit pas trop souvent SIGBUS de nos jours (autant que je sache).
De: ici
mmap
exemple minimal avec POSIX 7
"Erreur de bus" se produit lorsque le noyau envoie SIGBUS
à un processus.
Un exemple minimal qui le produit parce que ftruncate
a été oublié:
#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;
}
Courir avec:
gcc -std=c99 main.c -lrt
./a.out
Testé dans Ubuntu 14.04.
POSIX décritSIGBUS
comme:
Accès à une partie non définie d'un objet de la mémoire.
Le mmap spec dit que:
Les références comprises dans la plage d'adresses commençant par pa et se poursuivant pendant len octets aux pages entières suivant la fin d'un objet doivent entraîner la livraison d'un signal SIGBUS.
Et shm_open
dit que il génère des objets de taille 0:
L'objet de mémoire partagée a une taille de zéro.
Donc, à *map = 0
nous touchons au-delà de la fin de l'objet alloué.
Accès à la mémoire de pile non alignés dans ARMv8 aarch64
Cela a été mentionné à l'adresse suivante: Qu'est-ce qu'une erreur de bus? pour SPARC, mais je vais vous donner un exemple plus reproductible.
Tout ce dont vous avez besoin est un programme aarch64 autonome:
.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
Ce programme lève ensuite SIGBUS sur Ubuntu 18.04 aarch64, noyau Linux 4.15.0 dans un machine serveur ThunderX2 .
Malheureusement, je ne peux pas le reproduire en mode utilisateur QEMU v4.0.0, je ne sais pas pourquoi.
Le défaut semble être facultatif et contrôlé par les champs SCTLR_ELx.SA
et SCTLR_EL1.SA0
, j'ai résumé la documentation associée n peu plus loin ici .
Vous pouvez également obtenir SIGBUS lorsqu'une page de code ne peut pas être paginée pour une raison quelconque.
Certaines instances classiques d’erreur de bus, telles que SPARC (au moins certains SPARC, peut-être a-t-elle été modifiée), se produisent lorsque vous effectuez un accès mal aligné. Par exemple:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Cet extrait de code tente d'écrire la valeur entière 32 bits 0xdeadf00d
dans une adresse mal alignée (et probablement), et générera une erreur de bus sur les architectures "difficiles" à cet égard. Le x86 d'Intel est d'ailleurs pas une telle architecture, il autoriserait l'accès (bien que l'exécuter plus lentement).
Cela dépend de votre système d'exploitation, de votre processeur, de votre compilateur et éventuellement d'autres facteurs.
En général, cela signifie que le bus de la CPU ne peut pas exécuter une commande ou est sujet à un conflit, mais cela peut vouloir dire toute une gamme de choses en fonction de l'environnement et du code exécuté.
-Adam
Cela signifie normalement un accès non aligné.
Une tentative d'accès à une mémoire qui n'est pas physiquement présente provoquerait également une erreur de bus, mais vous ne la verrez pas si vous utilisez un processeur doté d'un MMU et d'un système d'exploitation qui n'est pas buggé. aucune mémoire non existante ne sera mappée sur l'espace d'adressage de votre processus.
Je recevais une erreur de bus lorsque le répertoire racine était à 100%.
Un exemple spécifique d'erreur de bus que je viens de rencontrer lors de la programmation de C sur OS X:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
Au cas où vous ne vous souviendriez pas de la documentation strcat
ajoutait le deuxième argument au premier en modifiant le premier argument (retournez les arguments et tout fonctionnera correctement). Sur Linux, cela donne une erreur de segmentation (comme prévu), mais sur OS X, cela donne une erreur de bus. Pourquoi? Je ne sais vraiment pas.
La raison de mon erreur de bus sur Mac OS X est que j'ai essayé d'allouer environ 1 Mo sur la pile. Cela fonctionnait bien dans un thread, mais lors de l’utilisation d’openMP, cela entraînait une erreur de bus, car Mac OS X n’avait que très peu de choses taille de la pile pour les threads non principaux .
Je suis d'accord avec toutes les réponses ci-dessus. Voici mes 2 cents concernant l'erreur de bus:
Une erreur de bus ne doit pas nécessairement résulter des instructions contenues dans le code du programme. Cela peut se produire lorsque vous exécutez un fichier binaire et que, pendant l'exécution, le fichier binaire est modifié (remplacé par une construction ou supprimé, etc.).
Vérifier si c'est le cas: Un moyen simple de vérifier si c'est la cause est en lançant des instances en cours d'exécution du même binaire et en exécutant une construction. Les deux instances en cours d'exécution plantaient avec une erreur SIGBUS
peu de temps après la fin de la construction et remplaçaient le binaire (celui sur lequel les deux instances sont en cours d'exécution)
Raison sous-jacente: Cela est dû au fait que le système d’échange échange des pages de mémoire et que, dans certains cas, le fichier binaire complet peut être stocké en mémoire. Ces plantages se produisent lorsque le système Le binaire a changé depuis sa dernière lecture.
Pour ajouter à ce que blxtd a répondu ci-dessus, des erreurs de bus se produisent également lorsque votre processus ne peut pas tenter d'accéder à la mémoire d'une "variable" particulière .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Notez l'utilisation ' par inadvertance ' de variable 'i' dans le premier 'pour boucle'? C'est ce qui cause l'erreur de bus dans ce cas.
Je viens de découvrir à la dure que, sur un processeur ARMv7, vous pouvez écrire du code qui vous donne une erreur de segmentation non optimisée, mais une erreur de bus lorsqu'il est compilé avec -O2 (optimisez davantage). J'utilise gcc bras gnueabihf compilateur croisé de Ubuntu x64.