Last time, we saw that installing an unhandled structured exception filter prevents the Microsoft Visual C++ runtime from converting unhandled C++ exceptions into std::
, because the C++ runtime itself uses the unhandled structured exception filter to do that conversion.
One option is to detect that your unhandled structured exception handler is observing an unhandled C++ exception, in which case you allow the call to pass through to the C++ unhandled exception handler so it can turn it into a std::
.
#define MSVC_EXCEPTION_CODE 0xE06D7363U LPTOP_LEVEL_EXCEPTION_FILTER previousFilter; std::terminate_handler previousTerminate; LONG CALLBACK MyUnhandledExceptionFilter( EXCEPTION_POINTERS *ExceptionInfo) { if (ExceptionInfo->ExceptionRecord.ExceptionCode == MSVC_EXCEPTION_CODE) { return previousFilter(ExceptionInfo); } CaptureDump(ExceptionInfo, UnhandledException::Structured); return EXCEPTION_EXECUTE_HANDLER; } void __cdecl my_terminate() { CaptureDump(nullptr, UnhandledException::Cpp); if (previousTerminate) { previousTerminate(); } else { std::abort(); } } void InstallCustomUnhandledExceptionFilters() { previousFilter = SetUnhandledExceptionFilter( MyUnhandledExceptionFilter); previousTerminate = std::set_terminate(my_terminate); }
The diagram looks like this:
Exception raised | ||
↓ | ||
Frame handler | (not handled) | |
↓ | ||
Frame handler | (not handled) | |
↓ | ||
â‹® | ||
↓ | ||
Frame handler | (not handled) | |
↓ | ||
MyUnhandled- ExceptionFilter |
not C++ → |
CaptureDump(Structured) |
↓ | ||
CppUnhandled- ExceptionFilter |
||
↓ | ||
std::terminate | → | CaptureDump(Cpp) |
But wait, why pass the C++ exception through to the runtime’s unhandled exception handler if we know that it’s just going to call our our custom terminate handler?¹ We can call the custom terminate handler directly.
#define MSVC_EXCEPTION_CODE 0xE06D7363U LONG CALLBACK MyUnhandledExceptionFilter( EXCEPTION_POINTERS *ExceptionInfo) { if (ExceptionInfo->ExceptionRecord.ExceptionCode == MSVC_EXCEPTION_CODE) { CaptureDump(ExceptionInfo, UnhandledException::Structured); } else { CaptureDump(ExceptionInfo, UnhandledException::Cpp); } return EXCEPTION_EXECUTE_HANDLER; } void InstallCustomUnhandledExceptionFilters() { previousFilter = SetUnhandledExceptionFilter( MyUnhandledExceptionFilter); }
Now the diagram looks like this:
Exception raised | ||||
↓ | ||||
Frame handler | (not handled) | |||
↓ | ||||
Frame handler | (not handled) | |||
↓ | ||||
â‹® | ||||
↓ | ||||
Frame handler | (not handled) | |||
↓ | ||||
MyUnhandled- ExceptionFilter |
→ | CaptureDump(Cpp) |  | If not C++ |
↘ | ||||
CaptureDump(Cpp) | Â | If C++ |
But wait, this is still not complete. There are ways for a program to terminate with an unhandled exception that don’t go through the unhandled exception filter. We’ll look at those next time.
¹ On reason is that from the custom terminate handler, you can use std::
to snoop on the exception that caused the termination (if there is one).
I’m very excited about this topic and would love to have it include how C++ exceptions are handled across the native/managed boundary when using C++/CLI code to call to native C++ code which then throws. In my experience, it’s quite tricky to get reliable call stacks in captured dmp files from this scenario.
Two small nitpicks:
In the last diagram, one CaptureDump(Cpp) -> CaptureDump(Structured)
In the (1) note: On reason -> One reason
Related to unhandled exceptions, how can you detect if another process terminates due to an unhandled exception? I need to write an app that does this, and have tried multiple techniques but none are completely reliable. I have tried:
1. Checking event viewer for crash records, but event viewer can be cleared by the user (or maybe even disabled?).
2. Monitor for WerFault.exe, and if found the command line for WerFault indicates which PID crashed. But I think WerFault can be disabled or replaced with another crash reporter.
3. Open the process of concern and...
I think your requirements make it such that this isn't possible. Here's a comparison: you want to know when your neighbor throws out a pizza box.
1. The trash bin could be emptied before you look. You'd have to poll constantly to detect this case.
2. Hook into the signal that the trash bin was opened and scan to see if what is being thrown away is a pizza box. But the neighbor could disable the signal and you'd have to poll constantly since the signal is fast and once and done.
3. Monitor the trash bin and whenever the lid...
Trivia: The three least significant bytes of the magic value decode as
msc
.