I have experienced a problem that the function I passed to the SetUnhandledExceptionFilter didn't get called when the exception code c0000374 raising. But it works fine with the exception code c0000005. Then I tried to use the AddVectoredExceptionHandler instead, and it didn't have the problem, the handler function get called correctly.
Is it the API bug? Can I use AddVectoredExceptionHandler instead of SetUnhandledExceptionFilter everywhere?
The both functions work correctly with
// Exception code c0000005
int* p1 = NULL;
*p1 = 99;
Only AddVectoredExceptionHandler can capture this exception. (To prove it doesn't depend on the runtime library, I raise the exception manually and it results the same.)
// Exception code c0000374
RaiseException(0xc0000374, 0, 0, NULL);
Test program.
#include <tchar.h>
#include <fstream>
#include <Windows.h>
LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
std::ofstream f;
f.open("VectoredExceptionHandler.txt", std::ios::out | std::ios::trunc);
f << std::hex << pExceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
f.close();
return EXCEPTION_CONTINUE_SEARCH;
}
LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
std::ofstream f;
f.open("TopLevelExceptionHandler.txt", std::ios::out | std::ios::trunc);
f << std::hex << pExceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
f.close();
return EXCEPTION_CONTINUE_SEARCH;
}
int _tmain(int argc, _TCHAR* argv[])
{
AddVectoredExceptionHandler(1, VectoredExceptionHandler);
SetUnhandledExceptionFilter(TopLevelExceptionHandler);
// Exception code c0000374
RaiseException(0xc0000374, 0, 0, NULL);
// Exception code c0000005
// int* p1 = NULL;
// *p1 = 99;
return 0;
}
It happens because of this code in MSVC CRT startup:
/*
* Enable app termination when heap corruption is detected on
* Windows Vista and above. This is a no-op on down-level OS's
* and enabled by default for 64-bit processes.
*/
if (!_NoHeapEnableTerminationOnCorruption)
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
}
If you want to disable it (not recommended), link nohetoc.obj
to your program.
The exception is actually caught directly at its source, in RtlReportCriticalFailure
, called by the heap manager once heap corruption is detected. The SEH handler registered in this function calls RtlReportException
, quickly followed by NtTerminateProcess
.
I can only conclude that SEH handlers are avoided on purpose -- with the heap corrupted, the stack contents (and therefore SEH registrations) are suspect too; and the application can't reasonably recover from heap corruption anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With