2010-01-18 15 views
10

¿Qué puede causar SIGBUS (error de bus) en una aplicación de usuario genérico x86 en Linux? Toda la discusión que he podido encontrar en línea se refiere a los errores de alineación de memoria, que por lo que entiendo no se aplica realmente a x86.Depuración SIGBUS en x86 Linux

(Mi código se ejecuta en un Geode, en caso de que existan peculiaridades específicos del procesador pertinentes allí.)

Respuesta

13

Puede obtener un SIGBUS de un acceso no alineado si enciende la trampa de acceso no alineada, pero normalmente está desactivada en un x86. También puede lograr que acceda a un dispositivo mapeado en memoria si hay algún tipo de error.

Su mejor opción es usar un depurador para identificar las instrucciones de fallas (SIGBUS es sincrónico) y tratar de ver lo que estaba tratando de hacer.

+1

El depurador mostró que el SIGBUS se produjo inmediatamente después de ingresar a la función. Tal vez tengo un poco de corrupción en la memoria, o tal vez uno de los parámetros de la función es malo? Tendré que verificar el desmontaje en el depurador para obtener más detalles si el error vuelve a ocurrir. –

+1

@Josh: compruebe para ver cuál es la instrucción que falla realmente: si es un impulso o pop, su puntero de pila está dañado. Si es algo más, entonces la dirección en la instrucción es el problema. –

0

Una causa común de fallo del bus en Linux x86 está tratando de eliminar la referencia de algo que no es realmente una puntero, o es un puntero salvaje. Por ejemplo, si no se inicializa un puntero, o se asigna un entero arbitrario a un puntero y luego se intenta desreferencia, normalmente se producirá una falla de segmentación o un error de bus.

La alineación se aplica a x86. Aunque la memoria en un x86 es direccionable por bytes (por lo que puede tener un puntero a cualquier dirección), si tiene, por ejemplo, un puntero a un entero de 4 bytes, ese puntero debe estar alineado.

Debe ejecutar su programa en gdb y determinar qué acceso al puntero genera el error de bus para diagnosticar el problema.

+4

El acceso desalineado de enteros funciona en x86. – Joshua

+5

no para instrucciones de SSE –

+3

Todas las instrucciones de carga/almacenamiento de SSE tienen versiones alineadas y no alineadas. Para accesos SSE (128 bits), funcionan a toda velocidad en las arquitecturas Intel actuales, por lo que no hay una penalización real al usar movimientos no alineados incondicionalmente (a menos que optimices al nivel que la longitud más corta de las instrucciones de movimiento alineadas es significativo, lo cual es poco probable). –

15

SIGBUS puede suceder en Linux por varias razones distintas de las fallas de alineación de memoria, por ejemplo, si intenta acceder a una región mmap más allá del final del archivo asignado.

¿Está utilizando algo como mmap, regiones de memoria compartida, o similar?

+2

Sí, estamos usando regiones de memoria compartida. Investigaré esa posibilidad la próxima vez que surja este error. Gracias. –

+0

mmap es necesariamente utilizado por cualquier programa que llame malloc, ya que hoy malloc es un forward to mmap. –

+0

@ v.oddou: Es mmap anónimo, que no tiene un concepto de "más allá del final del archivo asignado". – caf

3

Oh sí, hay una forma más extraña de obtener SIGBUS.

Si el kernel no puede abrir páginas en una página de códigos debido a la presión de la memoria (OOM killer debe estar deshabilitado) o la solicitud de IO ha fallado, SIGBUS.

0

Es un poco fuera de lo común, pero puede obtener un SIGBUS de una carga SSE2 no alineada (m128).

+2

¿Puedes? Normalmente resulta en #GP, que se asigna a SIGSEGV. – Ruslan

+1

Perdón, tienes razón. – Mischa

6

SIGBUS en x86 (incluido x86_64) Linux es una bestia rara. Puede aparecer desde un intento de acceso más allá del final del archivo ed mmap, o en algunas otras situaciones descritas por POSIX.

Pero por fallas de hardware no es fácil obtener SIGBUS. A saber, el acceso desalineado de cualquier instrucción, ya sea SIMD o no, generalmente da como resultado SIGSEGV. El desbordamiento de pila resulta en SIGSEGV. Incluso los accesos a direcciones que no están en forma canónica resultan en SIGSEGV. Todo esto debido a que #GP se está levantando, lo que casi siempre se asigna a SIGSEGV.

ahora, Acá algunas maneras de conseguir SIGBUS debido a una excepción de la CPU:

  1. bit de habilitación de CA en EFLAGS, y luego hacer el acceso no alineado por cualquier memoria de lectura o escritura de instrucciones. Vea this discussion para más detalles.

  2. Violación canónica a través de un registro de puntero de pila (rsp o rbp), generando #SS.He aquí un ejemplo para GCC (compilar con gcc test.c -o test -masm=intel):

 
int main() 
{ 
    __asm__("mov rbp,0x400000000000000\n" 
      "mov rax,[rbp]\n" 
      "ud2\n"); 
} 
1

Este brevemente fue mencionado anteriormente como "fallida solicitud IO", pero voy a ampliar un poco.

Un caso frecuente es cuando crece lentamente un archivo usando ftruncate, lo mapea en la memoria, comienza a escribir datos y luego se queda sin espacio en su sistema de archivos. El espacio físico para el archivo asignado se asigna a los fallos de página, si no queda ninguno, el proceso recibe un SIGBUS.

Si necesita que su aplicación se recupere correctamente de este error, tiene sentido reservar espacio explícitamente antes de mmap utilizando fallocate. Manejar ENOSPC en errno después de la llamada de interrupción es mucho más simple que tratar con señales, especialmente en una aplicación de subprocesos múltiples.

Cuestiones relacionadas