Pregunta

¿Diferencia entre un error de bus y una falla de segmentación? ¿Puede suceder que un programa produzca una falla seg y se detenga por primera vez y por segunda vez puede dar un error de bus y salir?

¿Fue útil?

Solución

En la mayoría de las arquitecturas que he usado, la distinción es que:

  • un SEGV se produce cuando accede a la memoria a la que no está destinado (por ejemplo, fuera de su espacio de direcciones).
  • un SIGBUS es causado debido a problemas de alineación con la CPU (por ejemplo, tratando de leer mucho desde una dirección que no es múltiplo de 4).

Otros consejos

SIGBUS también se generará si mmap () un archivo e intente acceder a parte del búfer asignado que se extiende más allá del final del archivo, así como por condiciones de error como falta de espacio. Si registra un controlador de señal utilizando sigaction () y usted establezca SA_SIGINFO , es posible que su programa examine la dirección de memoria defectuosa y maneje solo los errores de archivos asignados en la memoria.

Por ejemplo, un error de bus puede ser causado cuando su programa intenta hacer algo que el bus de hardware no admite. En SPARCs , por ejemplo, tratando de leer un valor de varios bytes (como un int, 32 -bits) de una dirección impar generó un error de bus.

Las fallas de segmentación ocurren, por ejemplo, cuando realiza un acceso que viola las reglas de segmentación, es decir, cuando intenta leer o escribir memoria que no le pertenece.

Supongo que está hablando de las señales SIGSEGV y SIGBUS definidas por Posix.

SIGSEGV ocurre cuando el programa hace referencia a una dirección no válida. SIGBUS es una falla de hardware definida por la implementación. La acción predeterminada para estas dos señales es terminar el programa.

El programa puede capturar estas señales e incluso ignorarlas.

Interpretando su pregunta (posiblemente de manera incorrecta) como que significa "Estoy recibiendo un SIGSEGV o un SIGBUS de forma intermitente, ¿por qué no es consistente?", vale la pena señalar que hacer cosas poco fiables con punteros no está garantizado por la C o C ++ estándares para dar lugar a una segfault; es solo un "comportamiento indefinido", que como profesor había dicho una vez, significa que en su lugar puede hacer que los cocodrilos emerjan de las tablas del piso y te coman.

Entonces, su situación podría ser que tiene dos errores, donde el primero que ocurre a veces causa SIGSEGV, y el segundo (si la falla predeterminada no ocurrió y el programa aún se está ejecutando) causa un SIGBUS.

Te recomiendo que pases con un depurador y busques cocodrilos.

Esto sería un duplicado de ¿Qué es un error de bus? , si no eran para el

  

¿Puede suceder que un programa produzca una falla seg y se detenga por primera vez y por segunda vez puede dar un error de bus y salir?

parte de la pregunta. Debería poder responder esto usted mismo con la información que se encuentra aquí.


  

Locura: hacer lo mismo una y otra vez y esperar resultados diferentes.
  - Albert Einstein


Por supuesto, tomando la pregunta literalmente ...

#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 programa que puede salir con una falla de segmentación en una ejecución y salir con un error de bus en otra ejecución.

  

¿Puede suceder que un programa produzca una falla seg y se detenga por primera vez y por segunda vez puede dar un error de bus y salir?

Sí, incluso para uno y el mismo error: Aquí hay un ejemplo serio pero simplista de macOS que puede producir tanto un error de segmentación (SIGSEGV) como un error de bus (SIGBUS), por índices fuera de los límites de una matriz, en un De manera determinista. El acceso no alineado mencionado anteriormente no es un problema con macOS. (¡Este ejemplo no causará ningún SIGBUS, si se ejecuta dentro de un depurador, lldb en mi caso!)

bus_segv.c:

#include <stdlib.h>

char array[10];

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

El ejemplo toma un número entero de la línea de comandos, que sirve como índice para la matriz. Hay algunos valores de índice (incluso fuera de la matriz) que no causarán ninguna señal. (Todos los valores dados dependen de los tamaños estándar de segmento / sección. Usé clang-902.0.39.1 para producir el binario en una CPU High Sierra macOS 10.13.5, i5-4288U @ 2.60GHz.)

Un índice por encima de 77791 y por debajo de -4128 causará una falla de segmentación (SIGSEGV). 24544 causará un error de bus (SIGBUS). Aquí el mapa completo:

$ ./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 observa el código desmontado, verá que los bordes de los rangos con errores de bus no son tan extraños como aparece el índice:

$ 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

Por leaq 0x96 (% rip),% rsi , rsi se convierte en (PC relativamente determinada) dirección de la dirección de inicio de la matriz:

<*>

lldb probablemente configura el proceso con diferentes límites de página. No pude reproducir ningún error de bus en una sesión de depuración. Por lo tanto, el depurador podría ser una solución para errores de bus que escupen binarios.

Andreas

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top