Question

Différence entre une erreur de bus et une erreur de segmentation? Peut-il arriver qu’un programme donne une erreur de segmentation et s’arrête pour la première fois et pour la deuxième fois il peut donner une erreur de bus et une sortie?

Était-ce utile?

La solution

Sur la plupart des architectures que j'ai utilisées, la distinction est la suivante:

  • un SEGV est provoqué lorsque vous accédez à de la mémoire que vous n’êtes pas censé (par exemple, en dehors de votre espace adresse).
  • un SIGBUS est dû à des problèmes d’alignement avec la CPU (par exemple, tentative de lecture longue d’une adresse qui n’est pas un multiple de 4).

Autres conseils

SIGBUS sera également généré si vous mmap () un fichier et une tentative d'accès à une partie du tampon mappé qui s'étend au-delà de la fin du fichier, ainsi que pour les conditions d'erreur telles que le manque d'espace. Si vous enregistrez un gestionnaire de signaux à l'aide de sigaction () et vous Si vous définissez SA_SIGINFO , il est possible que votre programme examine l'adresse mémoire défaillante et ne traite que les erreurs de fichier mappé en mémoire.

Par exemple, une erreur de bus peut survenir lorsque votre programme tente de faire quelque chose que le bus matériel ne prend pas en charge. Sur SPARC , par exemple, vous essayez de lire une valeur codée sur plusieurs octets (telle qu'une valeur int, 32 -bits) à partir d'une adresse impaire a généré une erreur de bus.

Les erreurs de segmentation se produisent, par exemple, lorsque vous effectuez un accès enfreignant les règles de segmentation, c’est-à-dire que vous essayez de lire ou d’écrire de la mémoire qui ne vous appartient pas.

Je suppose que vous parlez des signaux SIGSEGV et SIGBUS définis par Posix.

SIGSEGV se produit lorsque le programme fait référence à une adresse non valide. SIGBUS est une erreur matérielle définie par l'implémentation. L’action par défaut pour ces deux signaux est de terminer le programme.

Le programme peut capter ces signaux et même les ignorer.

En interprétant votre question (peut-être à tort) comme signifiant "Je reçois par intermittence un SIGSEGV ou un SIGBUS, pourquoi n'est-il pas cohérent?", il est intéressant de noter que le fait de faire des choses loufoques avec des pointeurs n'est pas garanti par le C ou Les normes C ++ entraînent une erreur de segmentation; c’est juste un "comportement indéfini", ce qui, en tant que professeur, l’a dit une fois: cela pourrait plutôt provoquer la sortie de crocodiles du plancher et vous dévorer.

Votre situation pourrait donc être due à deux bogues, le premier qui se produise parfois provoque SIGSEGV, et le second (si le défaut segfault n’a pas eu lieu et que le programme est toujours en cours d'exécution) provoque un SIGBUS.

Je vous recommande d'utiliser un débogueur et de rechercher des crocodiles.

Ce serait un dup de Qu'est-ce qu'une erreur de bus? , si elle n'étaient pas pour le

  

Peut-il arriver qu’un programme donne une erreur de segmentation et s’arrête pour la première fois et pour la deuxième fois il peut donner une erreur de bus et quitter le programme?

une partie de la question. Vous devriez pouvoir y répondre vous-même avec les informations trouvées ici.

  

Folie: faire la même chose encore et encore et attendre des résultats différents.
  - Albert Einstein

Bien sûr, prenant la question à la lettre ...

#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main() {
    srand(time(NULL));
    if (rand() % 2)
        kill(getpid(), SIGBUS);
    else
        kill(getpid(), SIGSEGV);
    return 0;
}

Tada, un programme qui peut sortir avec une erreur de segmentation sur une exécution et sortir avec une erreur de bus sur une autre exécution.

  

Peut-il arriver qu’un programme donne une erreur de segmentation et s’arrête pour la première fois et pour la deuxième fois il peut donner une erreur de bus et quitter le programme?

Oui, même pour un même bogue: Voici un exemple sérieux mais simpliste de macOS qui peut produire à la fois, erreur de segmentation (SIGSEGV) et erreur de bus (SIGBUS), par des index situés en dehors des limites d'un tableau, manière déterministe. L'accès non aligné mentionné ci-dessus n'est pas un problème avec macOS. (Cet exemple ne causera aucun SIGBUS, s’il s’exécute dans un débogueur, lldb dans mon cas!)

bus_segv.c:

#include <stdlib.h>

char array[10];

int main(int argc, char *argv[]) {
    return array[atol(argv[1])];
}

L'exemple prend un entier de la ligne de commande, qui sert d'index pour le tableau. Certaines valeurs d’index (même en dehors du tableau) ne généreront aucun signal. (Toutes les valeurs indiquées dépendent des tailles de segment / section standard. J'ai utilisé clang-902.0.39.1 pour produire le fichier binaire sur un processeur High Sierra macOS 10.13.5, i5-4288U à 2,60 GHz.)

Un index supérieur à 77791 et inférieur à -4128 provoquera un défaut de segmentation (SIGSEGV). 24544 provoquera une erreur de bus (SIGBUS). Voici la carte complète:

$ ./bus_segv -4129
Segmentation fault: 11
$ ./bus_segv -4128
...
$ ./bus_segv 24543
$ ./bus_segv 24544
Bus error: 10
...
$ ./bus_segv 28639
Bus error: 10
$ ./bus_segv 28640
...
$ ./bus_segv 45023
$ ./bus_segv 45024
Bus error: 10
...
$ ./bus_segv 53215
Bus error: 10
$ ./bus_segv 53216
...
$ ./bus_segv 69599
$ ./bus_segv 69600
Bus error: 10
...
$ ./bus_segv 73695
Bus error: 10
$ ./bus_segv 73696
...
$ ./bus_segv 77791
$ ./bus_segv 77792
Segmentation fault: 11

Si vous regardez le code désassemblé, vous voyez que les bordures des plages avec des erreurs de bus ne sont pas aussi étranges que l'index apparaît:

$ otool -tv bus_segv

bus_segv:
(__TEXT,__text) section
_main:
0000000100000f60    pushq   %rbp
0000000100000f61    movq    %rsp, %rbp
0000000100000f64    subq    
rsi = 0x100000f8a + 0x96 = 0x100001020
rsi - 4128 = 0x100000000 (below segmentation fault)
rsi + 24544 = 0x100007000 (here and above bus error)
rsi + 28640 = 0x100008000 (below bus error)
rsi + 45024 = 0x10000c000 (here and above bus error)
rsi + 53216 = 0x10000e000 (below bus error)
rsi + 69600 = 0x100012000 (here and above bus error)
rsi + 73696 = 0x100013000 (below bus error)
rsi + 77792 = 0x100014000 (here and above segmentation fault)
x10, %rsp 0000000100000f68 movl <*>x0, -0x4(%rbp) 0000000100000f6f movl %edi, -0x8(%rbp) 0000000100000f72 movq %rsi, -0x10(%rbp) 0000000100000f76 movq -0x10(%rbp), %rsi 0000000100000f7a movq 0x8(%rsi), %rdi 0000000100000f7e callq 0x100000f94 ## symbol stub for: _atol 0000000100000f83 leaq 0x96(%rip), %rsi 0000000100000f8a movsbl (%rsi,%rax), %eax 0000000100000f8e addq <*>x10, %rsp 0000000100000f92 popq %rbp 0000000100000f93 retq

Par leaq 0x96 (% rip),% rsi , rsi devient le (PC relativement déterminée) adresse de l’adresse de départ du tableau:

<*>

lldb configure probablement le processus avec différentes limites de pages. Je n'ai pas pu reproduire d'erreur de bus dans une session de débogage. Le débogueur peut donc constituer une solution de contournement pour les erreurs de bus générées par les erreurs de bus.

Andreas

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