2010-06-11 12 views
8

Tengo una aplicación de C++ que envuelve grandes partes de código en bloques de prueba. Cuando capturo excepciones, puedo devolver al usuario a un estado estable, lo cual es bueno. Pero ya no recibo basureros. Realmente me gustaría averiguar en qué parte del código se está produciendo la excepción, para poder registrarlo y solucionarlo.Obteniendo información sobre dónde se lanzan las excepciones C++ dentro del bloque de catch?

Ser capaz de obtener un volcado sin detener la aplicación sería ideal, pero no estoy seguro de que sea posible.

¿Hay alguna forma en que pueda averiguar dónde se lanzó la excepción desde dentro del bloque catch? Si es útil, estoy usando nativo msvC++ en Windows XP y superior. Mi plan es simplemente registrar los bloqueos en un archivo en las máquinas de los distintos usuarios y luego cargar los registros crash una vez que alcanzan un determinado tamaño.

+2

posible duplicado de [C++ muestra el seguimiento de la pila en la excepción] (http://stackoverflow.com/questions/691719/c-display-stack-trace-on-exception) – sth

Respuesta

5

Esto es posible con el uso de SEH (manejo estructurado de excepciones). El punto es que MSVC implementa las excepciones de C++ a través de SEH. Por otro lado, el SEH puro es mucho más poderoso y flexible.

Eso es lo que debes hacer. En lugar de utilizar C++ puro bloques try/catch como esta:

try 
{ 
    DoSomething(); 
} catch(MyExc& exc) 
{ 
    // process the exception 
} 

Usted debe situar el bloque de código interno DoSomething con el bloque SEH:

void DoSomething() 
{ 
    __try { 
     DoSomethingInner(); 
    } 
    __except (DumpExc(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) { 
     // never get there 
    } 
} 

void DumpEx(EXCEPTION_POINTERS* pExc) 
{ 
    // Call MiniDumpWriteDump to produce the needed dump file 
} 

es decir, dentro de la C++ try/catch que Coloque otro bloque SEH sin formato, que solo descarta todas las excepciones sin capturarlas.

Consulte here para ver un ejemplo del uso de MiniDumpWriteDump.

+1

El uso de SEH directamente está bien si no lo hace cuidado con la portabilidad. Las excepciones estándar de C++ son más portátiles (bueno, a excepción de varios compiladores para sistemas integrados que no admiten excepciones). – George

+2

Esta es una forma efectiva de manejar las excepciones de C++. Si desea obtener información útil sobre las excepciones del sistema operativo, como el desbordamiento de la pila o la violación del acceso, debe hacer que se llame a 'MiniDumpWriteDump' desde otro proceso. –

+0

@George: actualmente no hay forma portátil de obtener rastros de pila en C++. Me parece recordar que esta es una situación que el nuevo estándar C++ 0x intenta mejorar. –

1

Lo que necesita es analizar la pila para descubrir de dónde vino la excepción. Para msvc hay una lib llamada dbghelp.dll que puede ayudarlo a cerrar las excepciones. En general, lo que hago es cerrar la sesión de minidump file and use this to replay the issue junto a la base de datos del programa correcto (archivo pdb). Esto funciona en sistemas de clientes que no vienen con el código fuente o para los que no querrás dar pdbs.

1

Puede escribir volcados utilizando la función MiniDumpWriteDump.

Si está utilizando excepciones de C++, puede simplemente incluir información de archivo/línea/función (para que lo vea como texto si llama a std :: exception.what()) en cualquier lugar donde arroje esa excepción (usando ____FUNCTION____, ____FILE____ y ​​____LINE____ macros).

Si está tratando de atrapar las excepciones del sistema operativo, bloquear la aplicación probablemente sea una mejor opción.

1

Un truco que es independiente del compilador es envolver la instrucción throw en una función. La función puede realizar otras tareas antes de lanzar la excepción, como grabar en un archivo de registro. También es un lugar útil para poner un punto de quiebre. Si crea una macro para llamar a la función, puede incluir automáticamente el __FILE__ y el __LINE__ donde ocurrió el lanzamiento.

4

Es posible diseñar sus excepciones para incluir los nombres de los archivos de origen & números de línea. Para hacerlo, debe crear una clase derivada de std::exception para contener la información. En el siguiente ejemplo, tengo una biblioteca de excepciones para mi solicitud, que incluye my_exception. También tengo un traced_error que es una clase de excepción de plantilla derivada de mis excepciones de nivel de aplicación.La excepción traced_error contiene información sobre el número de línea del archivo & y llama al método de clase de excepción de nivel de aplicación 'what() para obtener información detallada del error.

#include <cstdlib> 
#include <string> 
#include <stdexcept> 
#include <iostream> 
using namespace std; 


template<class EX> 
class traced_error : virtual public std::exception, virtual public EX 
{ 
public: 
    traced_error(const std::string& file, int line, const EX& ex) 
    : EX(ex), 
     line_(line), 
     file_(file) 
    {  
    } 

    const char* what() const 
    { 
     std::stringstream ss; 
     static std::string msg; 
     ss << "File: " << file_ << " Line: " << line_ << " Error: " << EX::what(); 
     msg = ss.str().c_str(); 
     return msg.c_str(); 
    } 

    int line_; 
    std::string file_; 
}; 

template<class EX> traced_error<EX> make_traced_error(const std::string& file, int line, const EX& ex) 
{ 
    return traced_error<EX>(file, line, ex); 
} 


class my_exception : virtual public std::exception 
{ 
public: 
    my_exception() {}; 

    const char* what() const 
    { 
     return "my_exception's what"; 
    } 
}; 

#define throwx(EX) (throw make_traced_error(__FILE__,__LINE__,EX)) 


int main() 
{ 
    try 
    { 
     throwx(my_exception()); 
    } 
    catch(const std::exception& ex) 
    { 
     cout << ex.what(); 
    } 
    return 0; 
} 

La salida de este programa es:

File: .\main.cpp Line: 57 Error: my_exception's what

También puede rediseñar este modo que las excepciones a nivel de aplicación se derivan de traced_error en lugar de a la inversa, en caso de que prefiere coger específica excepciones de nivel de aplicación. En su catch, puede registrar el error en un archivo de registro & crear un archivo de volcado usando MiniDumpWriteDump().

Cuestiones relacionadas