Почему SetUnhandledExceptionFilter не может захватить какое-то исключение, но AddVectoredExceptionHandler может сделать
У меня возникла проблема, связанная с тем, что функция, которую я передал SetUnhandledExceptionFilter, не вызывалась при создании кода исключения c0000374. Но он отлично работает с кодом исключения c0000005.
Затем я попытался использовать AddVectoredExceptionHandler, и у него не было проблемы, функция обработчика получила правильное имя.
Это ошибка API? Можно ли использовать AddVectoredExceptionHandler вместо SetUnhandledExceptionFilter везде?
Обе функции корректно работают с
// Exception code c0000005
int* p1 = NULL;
*p1 = 99;
Только AddVectoredExceptionHandler может захватить это исключение. (Чтобы доказать, что это не зависит от библиотеки времени выполнения, я создаю исключение вручную, и это приводит к тому же.)
// Exception code c0000374
RaiseException(0xc0000374, 0, 0, NULL);
Программа тестирования.
#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;
}
Ответы
Ответ 1
Это происходит из-за этого кода при запуске MSVC CRT:
/*
* 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);
}
Если вы хотите отключить его (не), добавьте nohetoc.obj
в свою программу.
Ответ 2
Исключение фактически попадает непосредственно в его источник, в RtlReportCriticalFailure
, вызываемый менеджером кучи после обнаружения повреждения кучи. Обработчик SEH, зарегистрированный в этой функции, вызывает RtlReportException
, за которым быстро следует NtTerminateProcess
.
Я могу только заключить, что обработчиков SEH можно избежать специально - с повреждением кучи, содержимое стека (и, следовательно, регистрация SEH) также подозрительно; и приложение в любом случае не может нормально восстанавливаться из-за кучи.