¿Qué significa el mensaje "error de bus" y en qué se diferencia de un segfault?
¿Qué significa el mensaje "error de bus" y en qué se diferencia de un segfault?
Respuestas:
Los errores de bus son raros hoy en día en x86 y ocurren cuando su procesador ni siquiera puede intentar el acceso de memoria solicitado, típicamente:
Las fallas de segmentación ocurren cuando se accede a la memoria que no pertenece a su proceso, son muy comunes y generalmente son el resultado de:
PD: Para ser más precisos, esto no es manipular el puntero en sí mismo que causará problemas, es acceder a la memoria a la que apunta (desreferenciar).
/var/cache
era simplemente askubuntu.com/a/915520/493379
static_cast
editó un void *
parámetro a un objeto que almacena una devolución de llamada (un atributo apunta al objeto y el otro al método). Entonces se llama la devolución de llamada. Sin embargo, lo que se pasó void *
fue algo completamente diferente y, por lo tanto, la llamada al método causó el error del bus.
Un defecto de seguridad es acceder a la memoria a la que no puede acceder. Es de solo lectura, no tienes permiso, etc.
Un error del bus está intentando acceder a la memoria que posiblemente no puede estar allí. Ha utilizado una dirección que no tiene sentido para el sistema, o el tipo de dirección incorrecto para esa operación.
mmap
Ejemplo mínimo de POSIX 7
El "error de bus" ocurre cuando el núcleo envía SIGBUS
a un proceso.
Un ejemplo mínimo que lo produce porque ftruncate
fue olvidado:
#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;
}
Corre con:
gcc -std=c99 main.c -lrt
./a.out
Probado en Ubuntu 14.04.
POSIX describe SIGBUS
como:
Acceso a una porción indefinida de un objeto de memoria.
La especificación mmap dice que:
Las referencias dentro del rango de direcciones que comienzan en pa y continúan para bytes len a páginas enteras después del final de un objeto darán como resultado la entrega de una señal SIGBUS.
Y shm_open
dice que genera objetos de tamaño 0:
El objeto de memoria compartida tiene un tamaño de cero.
Entonces *map = 0
, estamos tocando más allá del final del objeto asignado.
Accesos de memoria de pila no alineados en ARMv8 aarch64
Esto se mencionó en: ¿Qué es un error de bus? para SPARC, pero aquí proporcionaré un ejemplo más reproducible.
Todo lo que necesitas es un programa independiente 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
Ese programa genera SIGBUS en Ubuntu 18.04 aarch64, Linux kernel 4.15.0 en una máquina de servidor ThunderX2 .
Desafortunadamente, no puedo reproducirlo en el modo de usuario QEMU v4.0.0, no estoy seguro de por qué.
La falla parece ser opcional y controlada por los campos SCTLR_ELx.SA
y SCTLR_EL1.SA0
, he resumido los documentos relacionados un poco más aquí .
Creo que el kernel genera SIGBUS cuando una aplicación exhibe desalineación de datos en el bus de datos. Creo que, dado que la mayoría de los compiladores modernos para la mayoría de los procesadores rellenan / alinean los datos para los programadores, los problemas de alineación de antaño (al menos) se mitigaron y, por lo tanto, uno no ve SIGBUS con demasiada frecuencia en estos días (AFAIK).
De: aquí
Una instancia clásica de un error de bus está en ciertas arquitecturas, como el SPARC (al menos algunos SPARC, tal vez esto ha cambiado), es cuando haces un acceso mal alineado. Por ejemplo:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Este fragmento intenta escribir el valor entero de 32 bits 0xdeadf00d
en una dirección que (muy probablemente) no esté alineada correctamente, y generará un error de bus en arquitecturas que son "exigentes" a este respecto. El procesador Intel x86 es, por cierto, no este tipo de arquitectura, que permitiría el acceso (aunque se ejecute más lentamente).
Un ejemplo específico de un error de bus que acabo de encontrar al programar C en OS X:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
En caso de que no recuerde, los documentos strcat
añaden el segundo argumento al primero cambiando el primer argumento (voltee los argumentos y funciona bien). En Linux, esto da un error de segmentación (como se esperaba), pero en OS X da un error de bus. ¿Por qué? Realmente no lo se.
"foo"
se almacena en un segmento de memoria de solo lectura, por lo que es imposible escribir en él. No sería protección contra desbordamiento de pila, solo protección contra escritura de memoria (este es un agujero de seguridad si su programa puede reescribirse).
Depende de su sistema operativo, CPU, compilador y posiblemente otros factores.
En general, significa que el bus de la CPU no pudo completar un comando o sufrió un conflicto, pero eso podría significar una gran variedad de cosas dependiendo del entorno y el código que se ejecuta.
-Adán
Normalmente significa un acceso no alineado.
Un intento de acceder a la memoria que no está físicamente presente también daría un error de bus, pero no verá esto si está utilizando un procesador con un MMU y un sistema operativo que no tiene errores, porque no tendrá -existente memoria asignada al espacio de direcciones de su proceso.
scanf
). ¿Eso significa que OS X Mavericks tiene errores? ¿Cuál habría sido el comportamiento en un sistema operativo sin errores?
Mi razón para el error del bus en Mac OS X fue que intenté asignar aproximadamente 1Mb en la pila. Esto funcionó bien en un subproceso, pero cuando se usa openMP esto conduce al error de bus, porque Mac OS X tiene un tamaño de pila muy limitado para subprocesos no principales .
Estoy de acuerdo con todas las respuestas anteriores. Aquí están mis 2 centavos con respecto al error del BUS:
No es necesario que surja un error de BUS a partir de las instrucciones dentro del código del programa. Esto puede suceder cuando está ejecutando un binario y durante la ejecución, el binario se modifica (sobrescrito por una compilación o eliminado, etc.).
Verificar si este es el caso:
una forma sencilla de verificar si esta es la causa es mediante la ejecución de instancias en ejecución del mismo binario y ejecutar una compilación. Ambas instancias en ejecución se bloquearían con un SIGBUS
error poco después de que la compilación haya finalizado y reemplazado el binario (el que ambas instancias están ejecutando actualmente)
Razón subyacente: Esto se debe a que el sistema operativo intercambia páginas de memoria y, en algunos casos, el binario podría no estar completamente cargado en la memoria y estos bloqueos se producirían cuando el sistema operativo intente recuperar la siguiente página del mismo binario, pero el binario ha cambiado desde la última vez Léelo.
Para agregar a lo que blxtd respondió anteriormente, los errores del bus también ocurren cuando su proceso no puede intentar acceder a la memoria de una 'variable' particular .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Observe el uso ' inadvertido ' de la variable 'i' en el primer 'for loop'? Eso es lo que está causando el error del bus en este caso.
Me acabo de enterar por las malas que en un procesador ARMv7 puede escribir un código que le da un error de segmentación cuando no está optimizado, pero le da un error de bus cuando se compila con -O2 (optimice más).
Estoy usando el compilador cruzado GCC ARM gnueabihf de Ubuntu 64 bit.
Un desbordamiento de búfer típico que produce un error de bus es,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Aquí, si el tamaño de la cadena entre comillas dobles ("") es mayor que el tamaño de buf, da error de bus.