segmentation generado error dumped c segmentation-fault sigsegv bus-error sigbus

generado - error segmentation fault c



Error de bus vs falla de segmentación (7)

¿Puede suceder que un programa dé 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 errores de segmentación (SIGSEGV) y errores de bus (SIGBUS), por índices fuera de los límites de una matriz, de una manera determinista. El acceso desalineado 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 a 2.60 GHz).

Un índice por encima de 77791 y por debajo de -4128 causará un error 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 desensamblado, verá que los límites 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 $0x10, %rsp 0000000100000f68 movl $0x0, -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 $0x10, %rsp 0000000100000f92 popq %rbp 0000000100000f93 retq

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

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)

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 alternativa para errores de bus escupir binarios.

Andreas

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


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

  • se genera un SEGV cuando accede a la memoria 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 un largo desde una dirección que no es un múltiplo de 4).

Esta sería una dupla de ¿Qué es un error de autobús? , si no fuera por el

¿Puede suceder que un programa dé 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 un error de segmentación en una ejecución y salir con un error de bus en otra ejecución.


Interpretando su pregunta (posiblemente incorrectamente) como "Estoy recibiendo un SIGSEGV o un SIGBUS de forma intermitente, ¿por qué no es consistente?", Vale la pena señalar que hacer cosas dudosas con punteros no está garantizado por los estándares C o C ++ para dar como resultado un segfault; es solo un "comportamiento indefinido", que como profesor lo había dicho una vez significa que en su lugar puede hacer que los cocodrilos emerjan de las tablas del piso y se los 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 segfault no sucedió y el programa aún se está ejecutando) causa un SIGBUS.

Te recomiendo que vengas con un depurador y busques cocodrilos.


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, intentar leer un valor de varios bytes (como un int, 32 bits) desde una dirección impar generó un error de bus.

Las fallas de segmentación suceden, por ejemplo, cuando usted hace un acceso que viola las reglas de segmentación, es decir, intenta leer o escribir en la memoria que no le pertenece.


Supongo que estás 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 captar estas señales e incluso ignorarlas.


También se generará SIGBUS si mmap() un archivo e intenta acceder a parte del búfer asignado que se extiende más allá del final del archivo, así como también para condiciones de error como falta de espacio. Si registra un manejador de señal usando sigaction() y configura SA_SIGINFO , es posible que su programa examine la dirección de memoria de fallas y maneje solo errores de archivos mapeados en la memoria.