为什么SetUnhandledExceptionFilter无法捕获一些异常,但AddVectoredExceptionHandler可以做到

时间:2013-10-29 11:26:02

标签: c++ windows winapi exception-handling

我遇到了一个问题,即当异常代码c0000374引发时,我传递给SetUnhandledExceptionFilter的函数没有被调用。但它可以正常使用异常代码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;
}

2 个答案:

答案 0 :(得分:12)

这是因为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与您的计划相关联。

答案 1 :(得分:4)

实际上,异常实际上是在RtlReportCriticalFailure的源代码中捕获的,一旦检测到堆损坏,就由堆管理器调用。在此函数中注册的SEH处理程序调用{​​{1}},然后快速跟随RtlReportException

我只能断定SEH处理程序是故意避免的 - 堆已损坏,堆栈内容(以及SEH注册)也是可疑的;无论如何,应用程序无法合理地从堆损坏中恢复。