Question

Qu'est-ce que "l'erreur de bus"? message signifie, et en quoi diffère-t-il d'une erreur de segmentation?

Était-ce utile?

La solution

Les erreurs de bus sont rares de nos jours sur x86 et se produisent lorsque votre processeur ne peut même pas tenter d'accéder à la mémoire demandée, généralement:

  • utiliser une instruction de processeur avec une adresse qui ne satisfait pas ses exigences d'alignement.

Les 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 résultent généralement de:

  • utiliser un pointeur sur quelque chose qui a été désalloué.
  • en utilisant un pointeur non initialisé, donc faux.
  • utilisant un pointeur nul.
  • déborder d'un tampon.

PS: Pour être plus précis, il ne s'agit pas d'une manipulation du pointeur lui-même susceptible de poser problème, mais d'un accès à la mémoire sur laquelle il pointe (déréférencement).

Autres conseils

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 impossible à atteindre. 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 élève SIGBUS   quand une application présente des données   défaut d'alignement sur le bus de données. je pense   que depuis la plupart [?] des compilateurs modernes   pour la plupart des processeurs pad / aligner le   données pour les programmeurs, les   problèmes d'alignement d'antan (au moins)   atténué, et donc on ne voit pas   SIGBUS trop souvent ces jours-ci (autant que je sache.)

De: ici

mmap exemple POSIX 7 minimal

" Erreur de bus " se produit lorsque le noyau envoie SIGBUS à un processus.

Un exemple minimal qui le produit car 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;
}

Exécuter avec:

gcc -std=c99 main.c -lrt
./a.out

Testé sous Ubuntu 14.04.

POSIX décrit SIGBUS en tant que:

  

Accès à une partie non définie d'un objet de la mémoire.

Le spécification mmap indique que:

  

Les références comprises dans la plage d'adresses commençant par pa et se poursuivant pendant len ??octets jusqu'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 Qu'est-ce qu'une erreur de bus? pour SPARC, mais je donnerai ici un exemple plus reproductible.

Tout ce dont vous avez besoin est d’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é les documents associés un bit plus loin .

Vous pouvez également obtenir SIGBUS lorsqu'une page de code ne peut pas être paginée pour une raison quelconque.

Certaines architectures, telles que le SPARC (par exemple, constituent une instance classique d'erreur de bus) au moins certains SPARC, peut-être cela a-t-il changé), est quand vous faites un accès mal aligné. Par exemple:

unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;

Cet extrait tente d'écrire la valeur entière 32 bits 0xdeadf00d sur une adresse mal alignée (et très probablement), et générera une erreur de bus sur les architectures "pointilleuses". à cet égard. Le x86 d’Intel est, d’ailleurs, pas une telle architecture, elle 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 l'unité centrale ne peut pas exécuter une commande ou est victime d'un conflit, mais cela peut vouloir dire 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 provoquerait également une erreur de bus, mais vous ne la verrez pas si vous utilisez un processeur avec une MMU et un système d'exploitation non buggé, car vous ne le ferez pas. avoir une mémoire non-existante mappée sur l'espace d'adressage de votre processus.

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.

Je recevais une erreur de bus alors que le répertoire racine était à 100%.

La raison de mon erreur de bus sous 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 taille de la pile pour les threads non principaux .

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 la variable 'i' dans premier "pour la 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 lorsque vous le compilez avec -O2 (optimisez davantage). J'utilise gcc bras gnueabihf compilateur croisé de Ubuntu x64.

Je suis d'accord avec toutes les réponses ci-dessus. Voici mes 2 centimes concernant l'erreur de bus:

Une erreur de bus ne doit pas nécessairement provenir des instructions contenues dans le code du programme. Cela peut se produire lorsque vous exécutez un binaire et que, pendant l'exécution, le binaire est modifié (remplacé par une construction ou supprimé, etc.).

Vérification si tel est le cas: Un moyen simple de vérifier si cela est la cause consiste à lancer des instances en cours d'exécution du même binaire et à exécuter 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'exploitation échange des pages de mémoire et que, dans certains cas, le binaire en entier peut être en mémoire et que ces blocages se produisent lorsque le système d'exploitation tente d'extraire la page suivante du même fichier binaire, mais le fichier binaire a été modifié depuis sa dernière lecture.

Un dépassement de tampon typique entraînant 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 du buf, cela donne une erreur de bus.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top