Tengo un programa que arroja una excepción no detectada en alguna parte. Todo lo que recibo es un informe de una excepción lanzada y ninguna información sobre dónde se lanzó. Parece ilógico que un programa compilado contenga símbolos de depuración que no me notifiquen en qué parte de mi código se generó una excepción.
¿Hay alguna forma de saber de dónde provienen mis excepciones a menos que establezca 'catch throw' en gdb y llame a un backtrace para cada excepción lanzada?
Respuestas:
Aquí hay información que puede ser útil para depurar su problema
Si no se detecta una excepción,
std::terminate()
se llama automáticamente a la función de biblioteca especial . Terminar es en realidad un puntero a una función y el valor predeterminado es la función de la biblioteca C estándarstd::abort()
. Si no se realizan limpiezas para una excepción no detectada † , en realidad puede ser útil para depurar este problema, ya que no se llaman destructores.† Está definido por la implementación si la pila se desenrolla o no antes de que
std::terminate()
se llame.Una llamada a
abort()
suele ser útil para generar un volcado de memoria que se puede analizar para determinar la causa de la excepción. Asegúrese de habilitar los volcados de núcleo a través deulimit -c unlimited
(Linux).Puede instalar su propia
terminate()
función usandostd::set_terminate()
. Debería poder establecer un punto de interrupción en su función de terminación en gdb. Es posible que pueda generar un seguimiento de pila a partir de suterminate()
función y este seguimiento puede ayudar a identificar la ubicación de la excepción.Hay una breve discusión sobre excepciones no detectadas en Thinking in C ++, 2nd Ed de Bruce Eckel que también puede ser útil.
Dado que las
terminate()
llamadasabort()
de forma predeterminada (lo que provocará unaSIGABRT
señal de forma predeterminada), es posible que pueda configurar unSIGABRT
controlador y luego imprimir un seguimiento de la pila desde dentro del controlador de señal . Este seguimiento puede ayudar a identificar la ubicación de la excepción.Nota: Digo que puede porque C ++ admite el manejo de errores no locales mediante el uso de construcciones de lenguaje para separar el manejo de errores y el código de informes del código ordinario. El bloque de captura puede estar, y a menudo está, ubicado en una función / método diferente al punto de lanzamiento. También se me ha señalado en los comentarios (gracias Dan ) que está definido por la implementación si la pila se desenrolla o no antes de
terminate()
llamar.Actualización: reuní un programa de prueba de Linux llamado que genera un backtrace en un
terminate()
conjunto de funciones viaset_terminate()
y otro en un controlador de señal paraSIGABRT
. Ambos backtraces muestran correctamente la ubicación de la excepción no controlada.Actualización 2: Gracias a una publicación de blog sobre cómo detectar excepciones no detectadas dentro de terminar , aprendí algunos trucos nuevos; incluido el relanzamiento de la excepción no detectada dentro del controlador de terminación. Es importante tener en cuenta que la
throw
declaración vacía dentro del controlador de terminación personalizado funciona con GCC y no es una solución portátil.Código:
Salida:
fuente
main
) y luego llamaríaterminate()
. Pero su ejemplo muestra que no se realiza ningún desenrollado, lo cual es muy bueno.throw(int)
especificación es innecesaria. 2)uc->uc_mcontext.eip
Probablemente dependa mucho de la plataforma (p. Ej., Se usa...rip
en una plataforma de 64 bits). 3) Compile con-rdynamic
para obtener símbolos de retroceso. 4) Corre./a.out 2>&1 | c++filt
para obtener bonitos símbolos de retroceso.((sig_ucontext_t *)userContext)->uc_mcontext.fault_address;
trabajó para mi objetivo de ARMComo dices, podemos usar 'catch throw' en gdb y llamar a 'backtrace' para cada excepción lanzada. Si bien eso suele ser demasiado tedioso para hacerlo manualmente, gdb permite la automatización del proceso. Eso permite ver el seguimiento de todas las excepciones que se lanzan, incluida la última no detectada:
gdb>
Sin más intervención manual, esto genera muchos rastreos, incluido uno para la última excepción no detectada:
Aquí hay una excelente publicación de blog que concluye esto: http://741mhz.com/throw-stacktrace [en archive.org]
fuente
Puede crear una macro como:
... y le dará la ubicación donde se lanza la excepción (es cierto que no el seguimiento de la pila). Es necesario que derive sus excepciones de alguna clase base que tome el constructor anterior.
fuente
throw new excation(...)
perothrow exception(...)
C ++ no es Java,No pasó información sobre el sistema operativo / compilador que utiliza.
En Visual Studio C ++ se pueden instrumentar excepciones.
Consulte "Instrumentación de manejo de excepciones de Visual C ++" en ddj.com
Mi artículo "Depuración post mortem" , también en ddj.com, incluye código para usar el manejo de excepciones estructurado de Win32 (usado por la instrumentación) para el registro, etc.
fuente
Puede marcar los lugares estrechos principales en su código
noexcept
para ubicar una excepción, luego use libunwind (solo agregue-lunwind
a los parámetros del vinculador) (probado conclang++ 3.6
):demagle.hpp:
demangle.cpp:
backtrace.hpp:
backtrace.cpp:
backtrace_on_terminate.hpp:
Hay un buen artículo sobre el tema.
fuente
Tengo un código para hacer esto en Windows / Visual Studio, avíseme si quiere un esquema. Sin embargo, no sé cómo hacerlo para el código dwarf2, una búsqueda rápida en Google sugiere que hay una función _Unwind_Backtrace en libgcc que probablemente sea parte de lo que necesita.
fuente
Revisa este hilo, quizás te ayude:
¿Detecta todas las excepciones de C ++ no controladas?
Tuve buenas experiencias con ese software:
http://www.codeproject.com/KB/applications/blackbox.aspx
Puede imprimir un seguimiento de pila en un archivo para cualquier excepción no controlada.
fuente
exception thrown foo.c@54, ..., re-thrown bar.c@54, ....
sin tener que hacerlo manualmente.