Cosa significa il messaggio "errore bus" e in cosa differisce da un segfault?
Cosa significa il messaggio "errore bus" e in cosa differisce da un segfault?
Risposte:
Gli errori di bus sono rari al giorno d'oggi su x86 e si verificano quando il processore non può nemmeno tentare l'accesso alla memoria richiesto, in genere:
Gli errori di segmentazione si verificano quando si accede alla memoria che non appartiene al processo, sono molto comuni e sono in genere il risultato di:
PS: Per essere più precisi, questo non sta manipolando il puntatore stesso che causerà problemi, ma accedendo alla memoria a cui punta (dereferenziazione).
/var/cache
era semplicemente askubuntu.com/a/915520/493379
static_cast
un void *
parametro su un oggetto che memorizza un callback (un attributo punta all'oggetto e l'altro al metodo). Quindi viene chiamato il callback. Tuttavia, ciò che è stato passato void *
era qualcosa di completamente diverso e quindi la chiamata del metodo ha causato l'errore del bus.
Un segfault sta accedendo alla memoria a cui non ti è permesso accedere. È di sola lettura, non hai il permesso, ecc ...
Un errore del bus sta tentando di accedere alla memoria che non può essere presente. Hai utilizzato un indirizzo privo di significato per il sistema o un tipo di indirizzo errato per tale operazione.
mmap
esempio di POSIX 7 minimo
"Errore bus" si verifica quando il kernel invia SIGBUS
a un processo.
Un esempio minimo che lo produce perché è ftruncate
stato dimenticato:
#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;
}
Corri con:
gcc -std=c99 main.c -lrt
./a.out
Testato su Ubuntu 14.04.
POSIX descrive SIGBUS
come:
Accesso a una parte indefinita di un oggetto memoria.
Le specifiche mmap dicono che:
I riferimenti all'interno dell'intervallo di indirizzi che iniziano con pa e continuano per len byte a pagine intere dopo la fine di un oggetto devono generare un segnale SIGBUS.
E shm_open
dice che genera oggetti di dimensione 0:
L'oggetto memoria condivisa ha una dimensione pari a zero.
Quindi, *map = 0
stiamo toccando oltre la fine dell'oggetto allocato.
Accessi di memoria stack non allineati in ARMv8 aarch64
Questo è stato menzionato in: Cos'è un errore del bus? per SPARC, ma qui fornirò un esempio più riproducibile.
Tutto ciò che serve è un programma aarch64 indipendente:
.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
Quel programma genera quindi SIGBUS su Ubuntu 18.04 aarch64, kernel Linux 4.15.0 in una macchina server ThunderX2 .
Sfortunatamente, non riesco a riprodurlo in modalità utente QEMU v4.0.0, non sono sicuro del perché.
L'errore sembra essere facoltativo e controllato dai campi SCTLR_ELx.SA
e SCTLR_EL1.SA0
, ho riassunto un po 'più avanti i relativi documenti .
Credo che il kernel sollevi SIGBUS quando un'applicazione mostra un disallineamento dei dati sul bus dati. Penso che dal momento che la maggior parte dei [?] Compilatori moderni per la maggior parte dei processori pad / allinea i dati per i programmatori, i problemi di allineamento del passato (almeno) mitigati, e quindi non si vede SIGBUS troppo spesso in questi giorni (AFAIK).
Da: qui
Un esempio specifico di un errore del bus che ho appena riscontrato durante la programmazione di C su OS X:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
Nel caso in cui non ricordi che i documenti strcat
aggiungono il secondo argomento al primo modificando il primo argomento (capovolgi gli argomenti e funziona benissimo). Su Linux questo dà un errore di segmentazione (come previsto), ma su OS X dà un errore del bus. Perché? Davvero non lo so.
"foo"
è memorizzato in un segmento di memoria di sola lettura, quindi è impossibile scriverlo. Non si tratterebbe di una protezione da overflow dello stack, ma solo di protezione da scrittura della memoria (questo è un buco di sicurezza se il tuo programma può riscrivere se stesso).
Un'istanza classica di un errore del bus è su alcune architetture, come lo SPARC (almeno alcuni SPARC, forse questo è stato modificato), è quando si fa un accesso errato. Per esempio:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Questo frammento tenta di scrivere il valore intero a 32 bit 0xdeadf00d
su un indirizzo (molto probabilmente) non correttamente allineato e genererà un errore del bus su architetture "difficili" in questo senso. A proposito, Intel x86 non è una tale architettura, consentirebbe l'accesso (anche se eseguirlo più lentamente).
Dipende dal tuo sistema operativo, CPU, compilatore e forse altri fattori.
In generale, significa che il bus della CPU non è stato in grado di completare un comando o ha subito un conflitto, ma ciò potrebbe significare un'intera gamma di cose a seconda dell'ambiente e del codice in esecuzione.
-Adamo
Normalmente significa un accesso non allineato.
Un tentativo di accedere alla memoria che non è fisicamente presente darebbe anche un errore del bus, ma non lo vedrai se stai usando un processore con una MMU e un sistema operativo che non sono buggy, perché non avrai alcun -esistente memoria mappata allo spazio degli indirizzi del processo.
scanf
). Ciò significa che OS X Mavericks è difettoso? Quale sarebbe stato il comportamento su un sistema operativo non difettoso?
La mia ragione per l'errore del bus su Mac OS X era che ho provato ad allocare circa 1 Mb nello stack. Questo ha funzionato bene in un thread, ma quando si utilizza openMP questo porta a errori di bus, poiché Mac OS X ha dimensioni dello stack molto limitate per thread non principali .
Sono d'accordo con tutte le risposte sopra. Ecco i miei 2 centesimi per quanto riguarda l'errore BUS:
Non è necessario che si verifichi un errore BUS dalle istruzioni all'interno del codice del programma. Questo può accadere quando si esegue un binario e durante l'esecuzione, il binario viene modificato (sovrascritto da una build o eliminato ecc.).
Verifica se questo è il caso:
un modo semplice per verificare se questa è la causa è avviando istanze in esecuzione dello stesso binario ed eseguendo una build. Entrambe le istanze in esecuzione si arresterebbero in modo anomalo con un SIGBUS
errore poco dopo il completamento della compilazione e la sostituzione del file binario (quello in cui entrambe le istanze sono attualmente in esecuzione)
Motivo sottostante: questo perché il sistema operativo scambia le pagine di memoria e in alcuni casi il binario potrebbe non essere completamente caricato in memoria e questi arresti anomali potrebbero verificarsi quando il sistema operativo tenta di recuperare la pagina successiva dallo stesso binario, ma il binario è cambiato dall'ultima volta leggilo.
Per aggiungere a ciò che ha risposto blxtd sopra, si verificano anche errori del bus quando il processo non può tentare di accedere alla memoria di una particolare 'variabile' .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Notate l'uso " involontario " della variabile "i" nel primo "ciclo"? Questo è ciò che sta causando l'errore del bus in questo caso.
Ho appena scoperto che su un processore ARMv7 puoi scrivere del codice che ti dà un errore di segmentazione quando non ottimizzato, ma ti dà un errore del bus quando compilato con -O2 (ottimizza di più).
Sto usando il compilatore cross Gnueabihf GCC ARM da Ubuntu 64 bit.
Un overflow del buffer tipico che provoca un errore del bus è,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Qui se la dimensione della stringa tra virgolette ("") è maggiore della dimensione del buf, si ottiene un errore del bus.