Why SetUnhandledExceptionFilter cannot capture some exception but AddVectoredExceptionHandler can do
Asked Answered
B

2

30

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;
}
Bounce answered 29/10, 2013 at 11:26 Comment(2)
The names suggest that the difference is that SetUnhandledExceptionFilter only gets called for unhandled exceptions. Have you considered the possibility that the C++ run-time library handles the other exception type internally?Shreve
@hvd I think that is possible. I will find a way to verify.Bounce
S
19

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.

Subdue answered 29/10, 2013 at 15:51 Comment(1)
Note it doesn't seem possible to disable this now, and no nohetoc.obj ships with Visual Studio 2019.Pleasurable
M
6

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.

Modernistic answered 29/10, 2013 at 12:24 Comment(1)
An application may not be able to recover from heap corruption. However, for diagnostic purposes, it is highly valuable to still write a minidump. In addition, 64-bit builds use table-based exception handling (vs. frame-based) anyway, so a corrupted heap and/or stack will not affect exception handling. I also don't follow your reasoning: You have followed the code down to the exception handler only to conclude that "SEH handlers are avoided on purpose". That didn't quite make sense.Elsieelsinore

© 2022 - 2024 — McMap. All rights reserved.