Domanda

Differenza tra un errore del bus e un errore di segmentazione? Può succedere che un programma dia un errore seg e si fermi per la prima volta e per la seconda volta possa dare un errore del bus ed uscire?

È stato utile?

Soluzione

Sulla maggior parte delle architetture che ho usato, la distinzione è che:

  • un SEGV è causato quando accedi alla memoria a cui non sei destinato (ad esempio, al di fuori del tuo spazio degli indirizzi).
  • un SIGBUS è causato da problemi di allineamento con la CPU (ad es., tentando di leggere un long da un indirizzo che non è un multiplo di 4).

Altri suggerimenti

SIGBUS verrà inoltre generato se mmap () un file e tenta di accedere a una parte del buffer mappato che si estende oltre la fine del file, nonché per condizioni di errore come spazio insufficiente. Se registri un gestore di segnali utilizzando sigaction () e tu impostare SA_SIGINFO , è possibile che il programma esamini l'indirizzo di memoria difettoso e gestisca solo errori di file associati alla memoria.

Ad esempio, un errore del bus potrebbe essere causato quando il programma tenta di fare qualcosa che il bus hardware non supporta. Su SPARCs , ad esempio, cercando di leggere un valore multi-byte (come un int, 32 -bit) da un indirizzo dispari ha generato un errore del bus.

Gli errori di segmentazione si verificano ad esempio quando si fa un accesso che viola le regole di segmentazione, ovvero quando si tenta di leggere o scrivere memoria che non si possiede.

Presumo che tu stia parlando dei segnali SIGSEGV e SIGBUS definiti da Posix.

SIGSEGV si verifica quando il programma fa riferimento a un indirizzo non valido. SIGBUS è un errore hardware definito dall'implementazione. L'azione predefinita per questi due segnali è di terminare il programma.

Il programma può catturare questi segnali e persino ignorarli.

Interpretazione della tua domanda (possibilmente errata) come significato " Ricevo a intermittenza un SIGSEGV o un SIGBUS, perché non è coerente? " ;, vale la pena notare che fare cose insicure con puntatori non è garantito dalla C o Standard C ++ per risultare in un segfault; è solo "un comportamento indefinito", che come professore avevo messo una volta significa che potrebbe invece far emergere coccodrilli dalle assi del pavimento e mangiarti.

Quindi la tua situazione potrebbe essere che hai due bug, in cui il primo che si verifica a volte causa SIGSEGV, e il secondo (se il segfault non si è verificato e il programma è ancora in esecuzione) causa un SIGBUS.

Ti consiglio di fare un passo avanti con un debugger e di cercare i coccodrilli.

Questo sarebbe un duplicato di Che cos'è un errore del bus? , se non erano per il

  

Può succedere che un programma dia un errore seg e si fermi per la prima volta e per la seconda volta potrebbe dare un errore del bus ed uscire?

parte della domanda. Dovresti essere in grado di rispondere da solo con le informazioni trovate qui.


  

Follia: fare sempre la stessa cosa e aspettarsi risultati diversi.
  - Albert Einstein


Ovviamente, prendi la domanda alla lettera ...

#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 programma che può uscire con un errore di segmentazione in una corsa e uscire con un errore del bus in un'altra corsa.

  

Può succedere che un programma dia un errore seg e si fermi per la prima volta e per la seconda volta potrebbe dare un errore del bus ed uscire?

Sì, anche per lo stesso bug: ecco un esempio serio ma semplicistico di macOS che può produrre sia un errore di segmentazione (SIGSEGV) che un errore del bus (SIGBUS), tramite indici al di fuori dei limiti di un array, in un modo deterministico. L'accesso non allineato di cui sopra non è un problema con macOS. (Questo esempio non causerà alcun SIGBUS, se viene eseguito all'interno di un debugger, lldb nel mio caso!)

bus_segv.c:

#include <stdlib.h>

char array[10];

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

L'esempio prende un numero intero dalla riga di comando, che funge da indice per l'array. Ci sono alcuni valori di indice (anche al di fuori dell'array) che non causeranno alcun segnale. (Tutti i valori forniti dipendono dalle dimensioni standard dei segmenti / sezioni. Ho usato clang-902.0.39.1 per produrre il binario su una CPU macOS 10.13.5 High Sierra, i5-4288U a 2,60 GHz.)

Un indice superiore a 77791 e inferiore a -4128 provocherà un errore di segmentazione (SIGSEGV). 24544 provocherà un errore del bus (SIGBUS). Ecco la mappa completa:

$ ./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

Se guardi il codice smontato, vedi che i bordi degli intervalli con errori del bus non sono così strani come appare l'indice:

$ 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

Di leaq 0x96 (% rip),% rsi , rsi diventa il (PC relativamente determinato) indirizzo dell'indirizzo iniziale dell'array:

<*>

lldb probabilmente imposta il processo con limiti di pagina diversi. Non sono stato in grado di riprodurre errori di bus in una sessione di debug. Quindi il debugger potrebbe essere una soluzione alternativa per l'errore del bus che sputa i binari.

Andreas

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top