Que signifie le message "erreur de bus" et en quoi diffère-t-il d'un défaut de segmentation?
Que signifie le message "erreur de bus" et en quoi diffère-t-il d'un défaut de segmentation?
Réponses:
Les erreurs de bus sont rares de nos jours sur x86 et se produisent lorsque votre processeur ne peut même pas tenter l'accès à la mémoire demandé, généralement:
Des erreurs de segmentation se produisent lors de l'accès à une mémoire qui n'appartient pas à votre processus, elles sont très courantes et sont généralement le résultat de:
PS: Pour être plus précis, ce n'est pas manipuler le pointeur lui-même qui causera des problèmes, c'est accéder à la mémoire vers laquelle il pointe (déréférencement).
/var/cache
était simplement pleine askubuntu.com/a/915520/493379
static_cast
édité un void *
paramètre sur un objet qui stocke un rappel (un attribut pointe vers l'objet et l'autre vers la méthode). Ensuite, le rappel est appelé. Cependant, ce qui a été transmis void *
était quelque chose de complètement différent et donc l'appel de méthode a provoqué l'erreur de bus.
Un segfault accède à la mémoire à laquelle vous n'êtes pas autorisé à accéder. C'est en lecture seule, vous n'avez pas la permission, etc ...
Une erreur de bus tente d'accéder à une mémoire qui ne peut pas exister. Vous avez utilisé une adresse qui n'a pas de sens pour le système ou le mauvais type d'adresse pour cette opération.
mmap
exemple minimal POSIX 7
Une "erreur de bus" se produit lorsque le noyau envoie SIGBUS
à un processus.
Un exemple minimal qui le produit car a ftruncate
é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écrit SIGBUS
comme:
Accès à une partie non définie d'un objet mémoire.
La spécification mmap dit que:
Les références dans la plage d'adresses commençant à pa et se poursuivant pendant len octets à des pages entières après la fin d'un objet entraîneront la livraison d'un signal SIGBUS.
Et shm_open
dit qu'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é à: Qu'est-ce qu'une erreur de bus? pour SPARC, mais ici je vais fournir un exemple plus reproductible.
Tout ce dont vous avez besoin est un programme autonome aarch64:
.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 sur une machine serveur ThunderX2 .
Malheureusement, je ne peux pas le reproduire en mode utilisateur QEMU v4.0.0, je ne sais pas pourquoi.
La faute semble être facultative et contrôlée par les champs SCTLR_ELx.SA
et SCTLR_EL1.SA0
, j'ai résumé les documents connexes un peu plus loin ici .
Je crois que le noyau soulève SIGBUS lorsqu'une application présente un désalignement des données sur le bus de données. Je pense que puisque la plupart des compilateurs modernes pour la plupart des processeurs remplissent / alignent les données pour les programmeurs, les problèmes d'alignement d'antan (au moins) atténués, et donc on ne voit pas SIGBUS trop souvent de nos jours (AFAIK).
De: ici
Vous pouvez également obtenir SIGBUS lorsqu'une page de codes ne peut pas être paginée pour une raison quelconque.
mmap
un fichier plus grand que la taille de/dev/shm
Une instance classique d'une erreur de bus se trouve sur certaines architectures, telles que le SPARC (au moins certains SPARC, peut-être que cela a été changé), c'est lorsque vous effectuez un accès mal aligné. Par exemple:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Cet extrait de code essaie d'écrire la valeur entière 32 bits 0xdeadf00d
dans une adresse qui (très probablement) n'est pas correctement alignée, et générera une erreur de bus sur les architectures qui sont "pointilleuses" à cet égard. Le Intel x86 n'est d'ailleurs pas une telle architecture, il autoriserait l'accès (quoiqu'il s'exécute plus lentement).
Un exemple spécifique d'une 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;
}
Dans le cas où vous ne vous souvenez pas, la documentation strcat
ajoute le deuxième argument au premier en changeant le premier argument (retournez les arguments et cela fonctionne bien). Sous Linux, cela donne un défaut de segmentation (comme prévu), mais sous OS X, cela donne une erreur de bus. Pourquoi? Je ne sais vraiment pas.
"foo"
est stocké dans un segment de mémoire en lecture seule, il est donc impossible d'y écrire. Ce ne serait pas une protection contre le débordement de pile, juste une protection en écriture mémoire (c'est un trou de sécurité si votre programme peut se réécrire).
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 CPU n'a pas pu exécuter une commande ou a subi un conflit, mais cela peut signifier toute une gamme de choses en fonction de l'environnement et du code en cours d'exécution.
-Adam
Cela signifie normalement un accès non aligné.
Une tentative d'accès à une mémoire qui n'est pas physiquement présente donnerait également une erreur de bus, mais vous ne le verrez pas si vous utilisez un processeur avec une MMU et un OS qui n'est pas bogué, car vous n'aurez pas de non -mémoire existante mappée à l'espace d'adressage de votre processus.
scanf
). Est-ce à dire que OS X Mavericks est buggé? Quel aurait été le comportement sur un système d'exploitation non bogué?
Ma raison de l'erreur de bus sur Mac OS X était que j'essayais d'allouer environ 1 Mo sur la pile. Cela fonctionnait bien dans un thread, mais lors de l'utilisation d'openMP, cela entraîne une erreur de bus, car Mac OS X a une taille de pile très limitée pour les threads non principaux .
Je suis d'accord avec toutes les réponses ci-dessus. Voici mes 2 cents concernant l'erreur BUS:
Une erreur de BUS n'a pas besoin de provenir des instructions dans le code du programme. Cela peut se produire lorsque vous exécutez un binaire et pendant l'exécution, le binaire est modifié (écrasé par une génération ou supprimé, etc.).
Vérifier si c'est le cas:
Un moyen simple de vérifier si c'est la cause est de lancer des instances en cours d'exécution du même binaire et d'exécuter une build. Les deux instances en cours d'exécution se bloqueraient avec une SIGBUS
erreur peu de temps après la fin de la génération et remplaceraient le binaire (celui que les deux instances exécutent actuellement)
Raison sous-jacente: cela est dû au fait que le système d'exploitation échange les pages de la mémoire et, dans certains cas, le binaire peut ne pas être entièrement chargé en mémoire et ces plantages se produisent lorsque le système d'exploitation tente de récupérer la page suivante du même binaire, mais le binaire a changé depuis sa dernière lis le.
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];
}
}
Vous remarquez l'utilisation « par inadvertance » de la variable «i» dans la première «boucle for»? 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 un défaut de segmentation lorsqu'il n'est pas optimisé, mais cela vous donne une erreur de bus lorsqu'il est compilé avec -O2 (optimisez davantage).
J'utilise le compilateur croisé GCC ARM gnueabihf d'Ubuntu 64 bits.
Un débordement de tampon typique qui entraîne une erreur de bus est,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Ici, si la taille de la chaîne entre guillemets ("") est supérieure à la taille buf, cela donne une erreur de bus.