我正在尝试改进异常诊断(更像是基本的崩溃处理),因为某些情况下SetUnhandledExceptionFilter
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx)似乎没有帮助捕获致命错误。这种情况是在关闭时运行不同的atexit函数和单例析构函数等(清理)。另外,由于noexcept声明不匹配而导致析构函数终止的情况也是一个问题。
确实使用AddVectoredExceptionHandler
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms679274(v=vs.85).aspx)似乎是一个很好的选择,因为它的功能更像是调试器的“第一次机会异常”,但它也因此被调用(方式)太多的情况(也是正常异常,某些信号等)。
由AddVectoredExceptionHandler
添加的VEH处理程序将在它们到达基于帧的处理程序之前处理异常。
由SetUnhandledExceptionFilter
设置的过滤器将在基于帧的处理程序失败后处理异常。
正常处理(如try...except
或try...catch
)和信号处理程序都实现为基于帧的处理程序,信号处理程序作为最后一个基于帧的处理程序。
在链条解开之前,没有可靠的方法来区分致命和非致命异常。语言异常(代码0xE06D7363
),其他软件异常和硬件异常(如代码0xC0000005
的访问冲突) - 都可能是致命的而且是非致命的。
因此,AddVectoredExceptionHandler
很难使用。除了set_terminate
之外,你还必须处理signal
,_set_invalid_parameter_handler
,SetUnhandledExceptionFilter
等。
您可以通过设置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()))
{
}
那么,你可以做的是添加矢量化异常处理程序,但实际上不检查那里的异常,但要么将其存储在某处(映射将线程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;
}