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.