筛选要与AddVectoredExceptionHandler一起使用的严重/致命异常

时间:2019-02-21 12:12:57

标签: c++ visual-c++ exception-handling c++17 terminate

在某些情况下,SetUnhandledExceptionFilterhttps://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx)似乎对捕获致命错误没有帮助,我正在尝试改进异常诊断(更像是基本的崩溃处理)。这种情况是在关闭时,不同的atexit函数和单例析构函数等正在运行(清理)。同样令人担忧的是,析构函数将因noexcept声明不匹配而终止。

实际上,使用AddVectoredExceptionHandlerhttps://msdn.microsoft.com/en-us/library/windows/desktop/ms679274(v=vs.85).aspx)似乎是一个不错的选择,因为它的功能更像是调试器的“第一次机会异常”,但是,它也因此被调用(太多)(以及正常的异常情况,某些信号等)。

  1. 理想情况下,有一种方法可以判断是否为异常
    将被处理,或者如果终止将被调用。
  2. 异常代码是另一种过滤方式-使用cpp 产生的抛出异常代码,很明显它应该继续- 我感觉这将是太多的尝试或尝试 以及错误的错误信息使“正确的”(致命)异常代码得以过滤。

2 个答案:

答案 0 :(得分:1)

AddVectoredExceptionHandler添加的

VEH处理程序将在到达基于帧的处理程序之前处理异常。

SetUnhandledExceptionFilter设置的过滤器将在基于帧的处理程序失败后处理异常。

两种常规处理(例如try...excepttry...catch)和信号处理程序都被实现为基于帧的处理程序,信号处理程序被实现为最后一个基于帧的处理程序。

在链解开之前,没有可靠的方法来区分致命非致命异常。语言异常(代码0xE06D7363),其他软件异常和硬件异常(例如代码0xC0000005的访问冲突)都可能是致命的,也可能是致命的。

因此,AddVectoredExceptionHandler几乎没有使用。除了set_terminate,您还必须处理signal_set_invalid_parameter_handlerSetUnhandledExceptionFilter等。

您可以通过设置signal来确保SIG_DFL的处理程序退回到默认值,在这种情况下,它将回退到SetUnhandledExceptionFilter设置的处理程序。

默认的_set_invalid_parameter_handler不会故意退回到SetUnhandledExceptionFilter设置的处理程序,但是如果您将传递给_set_invalid_parameter_handler的函数设置为引发自己的SEH异常,它将退回到处理程序由SetUnhandledExceptionFilter设置。

我不记得set_terminate和其他人怎么了。您需要尝试一下。但是作为最后的选择,您可能总是会引发自己的SEH异常,使用__except捕获它,并传递给UnhandledExceptionFilter,然后将调用您的SetUnhandledExceptionFilter回调:

__try
{
     RaiseException(0xE0000001,0,0,NULL);
}
__except(UnhandledExceptionFilter(GetExceptionInformation()))
{
}

答案 1 :(得分:0)

好吧,您可以做的是添加矢量化异常处理程序,但实际上不检查异常,而是将其存储在某个地方(将线程ID映射到异常信息的某些部分的映射)并安装终止处理程序-如果它将被调用,那么您知道映射中的异常之一就是错误的异常。为避免保留过多的数据,请在线程退出后添加线程本地raii类,该类将从映射中删除条目。当然,这会带来性能上的损失(在每次出现异常时都锁定地图),但是如果这确实是您想要的,那么这是一种有效的方法。

通用代码:

#include <exception>
#include <iostream>
#include <thread>

#include <Windows.h>

void termination_handler()
{
    // Look at the map, you will not know which one caused it but at least have all of them
    std::cout << "termination_handler called\n";
}

LONG VectoredExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo)
{
    // Put exception record somewhere - e.g map of thread ids to to exception record, maybe symbols
    return EXCEPTION_CONTINUE_SEARCH;
}

void foo()  
{
    throw std::exception();
}

int main(int argc, char** argv)
{
    AddVectoredExceptionHandler(0, VectoredExceptionHandler);
    std::set_terminate(termination_handler);
    std::thread t(foo);
    t.join();
    return 0;
}