Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why SetUnhandledExceptionFilter cannot capture some exception but AddVectoredExceptionHandler can do

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;
}
like image 762
wrongite Avatar asked Oct 29 '13 11:10

wrongite


2 Answers

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.

like image 96
Igor Skochinsky Avatar answered Oct 19 '22 21:10

Igor Skochinsky


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.

like image 5
avakar Avatar answered Oct 19 '22 21:10

avakar