Pregunta

Tengo un programa que a veces se separa de la aritmética de punteros.Sé que esto sucede, pero no puedo verificar fácilmente con anticipación si hay un error de segmentación o no; o puedo "escanear previamente" los datos de entrada para ver si causarán un error de segmentación (que puede ser imposible de determinar). o puedo reajustarlo para que no use aritmética de punteros, lo que requeriría una cantidad de trabajo significativamente mayor, o puedo intentar detectar un error de segmento.Entonces mi pregunta:

1) ¿Cómo, en C, puedo detectar un error de segmento?Sé algo en el sistema operativo causa una falla de segmentación, pero ¿qué puede hacer un programa en C en caso de que la falla de segmentación muera con un poco más de gracia que simplemente Segmentation fault?

2) ¿Qué tan portátil es esto?

Me imagino que este es un comportamiento altamente imposible de transportar, por lo que si publica algún código para detectar un error de segmento, dígame en qué funciona.Estoy en Mac OS X pero me gustaría que mi programa funcione en tantas plataformas como sea posible y quiero ver cuáles son mis opciones.

Y no te preocupes: básicamente todo lo que quiero hacer es imprimir un mensaje de error más fácil de usar y liberar algunos malloc()ed memoria, y luego morir.No planeo simplemente ignorar todos los fallos de segmentación que tengo y seguir adelante.

¿Fue útil?

Solución

Hay que definir un manejador de señales. Esto se hace en los sistemas Unix usando la función sigaction . He hecho esto con el mismo código en Fedora 64 y 32 bits, y en Sun Solaris.

Otros consejos

Bueno, SIGSEGV es capturable, y esto es POSIX, por lo que es portátil en ese sentido.

Bu Me preocupa que parece que quieres para manejar el error de segmentación en lugar de solucionar el problema que causa la violación de segmento. Si tuviera que elegir si era el sistema operativo en falta, o mi propio código, sé lo que yo elegiría. Le sugiero que cazar a ese error, corregirlo, a continuación, escribir un caso de prueba para asegurarse de que nunca te pica a otra persona.

Puede utilizar la función señal para instalar un nuevo controlador de señal para la señal:

   #include <signal.h>
   void (*signal(int signum, void (*sighandler)(int)))(int);

Algo así como el código siguiente:

signal(SIGINT , clean_exit_on_sig);
signal(SIGABRT , clean_exit_on_sig);
signal(SIGILL , clean_exit_on_sig);
signal(SIGFPE , clean_exit_on_sig);
signal(SIGSEGV, clean_exit_on_sig); // <-- this one is for segmentation fault
signal(SIGTERM , clean_exit_on_sig);

void 
clean_exit_on_sig(int sig_num)
{
        printf ("\n Signal %d received",sig_num);
}

Las acciones de seguridad en un manejador de señales son muy limitada. No es seguro para llamar a cualquier función de la biblioteca no se sabe que sean reentrantes, que excluye, por ejemplo, free() y printf(). La mejor práctica es establecer una variable y el regreso, pero esto no le ayuda mucho. También es seguro de usar las llamadas al sistema como write().

Tenga en cuenta que en los dos ejemplos dados aquí backtrace, la función backtrace_symbols_fd() estará a salvo, ya que utiliza la materia prima FD directamente, pero la llamada a fprintf() es incorrecta, y debe ser reemplazado por un uso de write().

Creo que está tratando de resolver un problema que no existe. Por lo menos se está trabajando en el lado equivocado. Usted no será capaz de captura un fallo de segmentación, ya que este error / excepción es lanzada por el sistema operativo (que es provocó por su programa, el sistema operativo simplemente capturas es).

Le aconsejo que reconsiderar su estrategia con respecto a la entrada: ¿Por qué es imposible desinfectar? El más importante es la comprobación de tamaño, para este stdlib el C tiene funciones apropiadas. Luego, por supuesto que tendría que comprobar si hay una entrada válida en cuanto al contenido. Sí, esto probablemente va a dar lugar a una gran cantidad de trabajo, pero es la única manera de escribir un programa robusto.

editar No soy mucho de un experto en C, no sabía que incluso un fallo de segmentación podría ser manejado por un manejador de señales. Aún así, creo que no es el camino correcto a seguir por las razones mencionadas anteriormente.

Usted tendrá que proporcionar un controlador SIGSEGV, éste ve bastante decente .

El manejo de señales es (relativamente) portátil en máquinas Unix (esto incluye Mac y Linux).Las grandes diferencias están en el detalle de la excepción, que se pasa como argumento a la rutina de manejo de señales.Lo siento, pero probablemente necesitarás un montón de #ifdefs para eso, si deseas imprimir mensajes de error más razonables (como dónde y por qué dirección ocurrió la falla)...

Bien, aquí tienes un fragmento de código para empezar:

#include <signal.h>

/* reached when a segv occurrs */
void
SEGVFunction( SIGARGS )
{
     ...
}

...
main(...) {
    signal(SIGSEGV, SEGVFunction); /* tell the OS, where to go in case... */
    ...
    ... do your work ...
}

Tu tarea es:

  • verifique qué es SIGARGS (depende del sistema operativo, así que use un ifdef)
  • vea cómo extraer la dirección de error y la PC de la información de excepción en sigArgs
  • imprimir mensaje razonable
  • salida

en teoría, incluso podría parchear la computadora en el controlador de señales (después de la instrucción defectuosa) y continuar.Sin embargo, los manejadores de señales típicos salen() o regresan a un longjmp() a un lugar guardado en el archivo principal.

saludos

Hay un ejemplo de cómo coger SIGSEGV e imprimir un seguimiento de la pila utilizando traza de glibc () aquí:

cómo generar un StackTrace cuando mi C ++ aplicación se bloquea

Puede usar esto para recuperar el error de segmentación y limpiar, pero ten cuidado: no se debe hacer demasiadas cosas en un manejador de señales, especialmente cosas que involucran realización de llamadas como malloc (). Hay una gran cantidad de llamadas que no son señales de seguridad, y se puede llegar a pegarse un tiro en el pie si se hace, por ejemplo, una llamada a malloc desde dentro malloc.

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