c++ - Excepciones atrapadas silenciosamente por Windows, ¿cómo manejarlas manualmente?
mfc exception (7)
Estamos teniendo problemas con el hecho de que Windows come silenciosamente excepciones y permite que la aplicación continúe ejecutándose, cuando se lanza la excepción dentro de la bomba de mensajes. Por ejemplo, creamos una aplicación MFC MDI de prueba y reemplazamos OnDraw:
void CTestView::OnDraw(CDC* /*pDC*/)
{
*(int*)0 = 0; // Crash
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
}
Esperaría un desagradable mensaje de error cuando ejecuta la aplicación, pero en realidad no obtiene nada en absoluto. El programa parece funcionar perfectamente, pero si revisas la ventana de salida, verás:
Excepción de primera oportunidad en 0x13929384 en Test.exe: 0xC0000005: ubicación de escritura de violación de acceso 0x00000000.
Excepción de primera oportunidad en 0x77c6ee42 en Test.exe: 0xC0150010: El contexto de activación que se está desactivando no está activo para el hilo de ejecución actual.
Sé por qué recibo la excepción de contexto de la aplicación, pero ¿por qué se maneja de forma silenciosa? Significa que nuestras aplicaciones podrían sufrir graves problemas cuando están en uso, pero nunca lo sabremos, porque nuestros usuarios nunca reportarán ningún problema.
Tu salida parece que estás usando Visual Studio ...
Si no, olvídate de mi respuesta.
Puede especificar qué excepciones se lanzarán normalmente, lo que significa que Visual Studio las detecta y su programa se detiene donde ocurrió la violación de acceso. Haga esto en el menú Depurar / Excepciones ... Si no está seguro de qué habilitar, simplemente habilítelos a todos ...
funciones que pueden ser de interés:
SetUnhandledExceptionFilter()
_set_invalid_parameter_handler()
_RTC_SetErrorFuncW()
_CrtSetReportHookW2()
PD, tenga en cuenta que SetUnhandledExceptionFilter () puede ser reemplazado por otros dlls cargados en su .exe. por ejemplo, flash y nvidia direct3d hacen esto. Yo uso api hooking para curar esto.
Si está ejecutando un sistema operativo x64 es posible que haya sido mordido por esto:
O (menos probable en este caso), puede ser este: http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx
RESPUESTA EN HINDSIGHT para cualquier persona que tropiece con esto más tarde.
Esto fue causado por un problema conocido en Windows http://support.microsoft.com/kb/976038 : asegúrese de estar actualizado, instale el parche caliente si es necesario y marque su aplicación como compatible con Windows 7. http://msdn.microsoft.com/en-us/library/dd371711%28v=vs.85%29.aspx
Lo he visto con los códigos de excepción c015000f y c0150010.
Experimenté este mismo problema y descubrí que era el resultado de este error de Microsoft: http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught -in-wndproc-mensajes
Hay una solución disponible de Microsoft, aunque su implementación es un poco desafiante si tiene múltiples plataformas de destino:
http://support.microsoft.com/kb/976038
Aquí hay un artículo sobre el tema que describe el comportamiento:
El problema es básicamente que las excepciones de hardware en programas de 32 bits se capturan silenciosamente en la rutina WndProc en sistemas operativos de 64 bits, a menos que envíe comandos que indiquen que no. Microsoft tiene una revisión para el problema que se requiere si está ejecutando Vista SP2, pero no es necesario con Windows 7 SP1 (no estoy seguro acerca de Win7 sin el SP).
Incluso con la revisión, debe habilitar el comportamiento correcto configurando una clave de registro o haciendo algunas llamadas al kernel para indicarle que su proceso espera que las excepciones de hardware se bloqueen cuando se encuentre durante WndProc.
De acuerdo con el enlace de PaulBetts anterior, esto se hizo por compatibilidad con Windows Server 2003.
Si programa es un programa de 64 bits, este problema desaparece.
Después de examinar preguntas similares, me encontré con esta respuesta: OpenGL suprime las excepciones en la aplicación basada en cuadros de diálogo MFC
"Ok, descubrí algo más de información sobre esto. En mi caso, es Windows 7 que instala KiUserCallbackExceptionHandler como manejador de excepciones, antes de llamar a mi WndProc y darme control de ejecución. Esto es hecho por ntdll! KiUserCallbackDispatcher. Sospecho que esto es una seguridad medida tomada por Microsoft para evitar la piratería en SEH.
La solución es envolver su wndproc (o hookproc) con un marco try / except ".
He archivado un informe de error con Microsoft, puede ver su respuesta aquí:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages
De Microsoft:
Gracias por el informe. Descubrí que se trata de un problema de Windows y hay una solución urgente disponible. Consulte http://support.microsoft.com/kb/976038 para obtener una solución que puede instalar si lo desea.
Puede forzar a Windows a que no ignore las excepciones con este fragmento de código (de las Excepciones de Microsoft que se lanzan desde una aplicación que se ejecuta en una versión de Windows de 64 bits se ignoran ) que pondrá en su código de proceso:
// my SDK is v6.0A and the two APIs are not available in the .h files, so I need to get them at runtime
#define PROCESS_CALLBACK_FILTER_ENABLED 0x1
typedef BOOL (WINAPI *GETPROCESSUSERMODEEXCEPTIONPOLICY)(__out LPDWORD lpFlags);
typedef BOOL (WINAPI *SETPROCESSUSERMODEEXCEPTIONPOLICY)(__in DWORD dwFlags );
HINSTANCE h = ::LoadLibrary(L"kernel32.dll");
if ( h ) {
GETPROCESSUSERMODEEXCEPTIONPOLICY GetProcessUserModeExceptionPolicy = reinterpret_cast< GETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "GetProcessUserModeExceptionPolicy") );
SETPROCESSUSERMODEEXCEPTIONPOLICY SetProcessUserModeExceptionPolicy = reinterpret_cast< SETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "SetProcessUserModeExceptionPolicy") );
if ( GetProcessUserModeExceptionPolicy == 0 || SetProcessUserModeExceptionPolicy == 0 ) {
return;
}
DWORD dwFlags;
if (GetProcessUserModeExceptionPolicy(&dwFlags)) {
SetProcessUserModeExceptionPolicy(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED);
}
}
Puede ser que tenga que agregar también un filtro de excepciones no controladas : el filtro actúa como un "controlador de excepción de nivel superior" que es como un bloque catch
superior. Para extraer una cadena amigable para programadores de _EXCEPTION_POINTERS, puede ver ¿Hay alguna función para convertir EXCEPTION_POINTERS struct en una cadena?
LONG WINAPI my_filter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
{
::OutputDebugStringA("an exception occured!");
return EXCEPTION_EXECUTE_HANDLER;
}
Usted agrega el filtro con:
::SetUnhandledExceptionFilter(my_filter);
y tiene que hacerlo en todos los hilos de su proceso: mientras que el fragmento anterior es por proceso, el filtro es por subproceso.