Подтвердить что ты не робот

Почему 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;
}
4b9b3361

Ответ 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) также подозрительно; и приложение в любом случае не может нормально восстанавливаться из-за кучи.