propiedades - ¿Cómo construir un contenedor C++ Dll que capte todas las excepciones?
manejo de excepciones personalizadas c# (8)
¿Has mirado la función API de Windows SetUnhandledExceptionFilter?
Normalmente lo llamo en la función DllMain y hago que genere un minivolcado cuando el DLL se cuelga. Sin embargo: (a) no sé si atrapa las excepciones de aplicación y las excepciones de DLL, y (b) no sé si puede hacer que el controlador regrese de tal forma que la ejecución del programa pueda continuar. Los documentos dicen que sí, pero nunca lo hice.
Como dice el título, estamos buscando una forma de capturar todas las excepciones de un fragmento de código C ++ y envolverlo en un dll. De esta forma podemos proteger de la aplicación que usa este dll, de cualquier error que ocurra en este dll.
Sin embargo, esto no parece posible con C ++ en Windows.
Ejemplo:
void function()
{
try
{
std::list<int>::iterator fd_it;
fd_it++;
} catch(...) {}
}
La excepción que se produce no es capturada por el bloque try / catch estándar de C ++, ni por ninguna función de traducción SEH establecida por _set_se_translator()
. En cambio, el DLL se bloquea y el programa que usa el DLL se cancela. Compilamos con Visual C ++ 2005, con la opción / SHa. ¿Alguien sabe si es posible en C ++ / Win32 detectar este tipo de problemas y crear un contenedor DLL sólido?
En Windows, C ++ tiene 2 estilos diferentes de excepciones: excepciones C ++ y SEH.
SEH es una forma de excepción de windows (similar a las señales en UNIX). Es más una excepción de nivel de sistema. Se lanzarán para operaciones tales como accesos de puntero no válidos, problemas de alineación, etc.
Si desea capturar cada excepción que pueda lanzar una aplicación C ++ en Windows, necesitará capturar ambas. Afortunadamente, hay una manera de mezclar el uso de las excepciones C ++ y SEH. Escribí una publicación detallada del blog sobre esto recientemente, debería ayudarte.
http://blogs.msdn.com/jaredpar/archive/2008/01/11/mixing-seh-and-c-exceptions.aspx
Incrementar un iterador en un contenedor estándar de libary nunca arrojará una excepción de C ++. Puede darte un comportamiento indefinido.
La única forma de hacer un contenedor DLL sólido como una roca es cargar el DLL con errores en otro proceso, de modo que si se bloquea no se lleva consigo el proceso primario.
Ver todas las excepciones de C ++ parece razonable, pero capturar todas las excepciones estructuradas es otra historia. Puede que SEH te lleve la mayor parte del camino hasta allí, porque te permite detectar infracciones de acceso, excepciones de división por cero, etc.
¿Pero qué pasa si la DLL con errores llega a tocar una página no confirmada de la pila de otro hilo? El acceso a la memoria generará un error de página, se invocará al controlador de excepción y ahora esa página ya no es una página de protección. Cuando ese hilo necesite aumentar la pila, obtendrá una violación de acceso y el proceso se bloqueará. ( Estas publicaciones describen este caso con más detalle).
Otro problema probable: el DLL defectuoso falla mientras se mantiene un objeto de sincronización, pero usted usa SEH para detectar la excepción. Si su proceso intenta adquirir el mismo objeto de sincronización, se bloquea en lugar de bloquearse. El objeto de sincronización compartido puede ser parte del tiempo de ejecución de C o del sistema operativo: ¿qué ocurre si la DLL 1 con errores carga DLL 2 con errores, que se bloquea en su DllMain()
mientras DLL 1 con errores mantiene el bloqueo del cargador? ¿Su proceso se estancará la próxima vez que cargue una DLL?
Para obtener más información sobre por qué esto (y funciona como IsBadReadPtr()
, que tienen problemas similares) es un uso indebido de SEH:
- WebLog de Larry Osterman: Manejo de excepciones estructuradas considerado dañino
- WebLog de Larry Osterman: ¿Debería verificar los parámetros de mi función?
- WebLog de Larry Osterman: La resiliencia NO es necesariamente algo bueno
- The Old New Thing: IsBadXxxPtr realmente debería llamarse CrashProgramRandomly
Este código contiene un error de lógica, si es que lo tiene. Dado que un error de lógica constituye un error, no trague la excepción - ¡ solucione el error !
Por supuesto, esto es específico para el código particular. Otros han ofrecido un consejo más general. Sin embargo, he descubierto que mucha gente realmente prefiere detectar excepciones sobre la corrección de errores de lógica y esto es simplemente inaceptable.
El siguiente código está tomado del Zeus IDE. Atrapará cualquier excepción generada por Windows:
Paso # 1: defina una función de filtro de excepción
DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
{
//-- we handle all exceptions
DWORD dwResult = EXCEPTION_EXECUTE_HANDLER;
switch (dwException)
{
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_BREAKPOINT:
dwResult = EXCEPTION_EXECUTE_HANDLER;
break;
}
return dwResult;
}
Paso # 2: ajusta el código en __try y __except como se muestra a continuación:
__try
{
// call your dll entry point here
}
__except(ExceptionFilter(GetExceptionInformation(),
GetExceptionCode()))
{
//-- display the fatal error message
MessageBox(0, "An unexpected error was caught here!",
"Unexpected Error", MB_OK);
}
¿Qué vas a hacer después de atrapar la excepción (especialmente para las excepciones de SEH)?
En realidad, no puede hacer suposiciones sobre el estado del proceso, de manera realista, la única opción que tiene es (opcionalmente) volcar núcleo y salir.
Cualquier intento y procedimiento absolutamente le causará problemas a largo plazo.
Konrad Rudolph: Por supuesto, este código contiene un "error de lógica", es para ilustrar un problema que podría ocurrir. Al igual que el hombre dice que quiere ser capaz de proteger su dll de posibles errores. ¿No crees que esta es una pregunta legítima? Oído de los productos del vendedor. Algunos de nosotros vivimos en el mundo real y vivimos con problemas reales. Simplemente no es posible solucionar los problemas de los demás