捕获Windows上的访问违规

Catching access violations on Windows

本文关键字:访问 Windows 捕获      更新时间:2023-10-16

我试图捕获应用程序中所有未处理的异常,以便在它们发生时保存日志文件。这是一个64位的Windows应用程序,使用Visual Studio 2013编译,用c++编写。为了测试,我使用的是VS.生成的默认c++ Win32项目。

我通过使用SetUnhandledExceptionFilter注册处理程序来捕获所有异常。这适用于大多数情况,但不是全部。所有throw()-n异常都会被捕获,大多数硬件异常(如浮点数或访问违规)也会被捕获。不触发处理程序的代码是:

std::vector<int> foo(5, 0);
for (auto& f : foo)
    foo.erase(foo.begin() + 1);

相反,我只是得到标准的windows崩溃对话框,没有我的异常处理程序被调用。但是,如果我在Visual Studio中附带调试器运行它,它会正确报告访问冲突异常。其他类型的访问违规也会触发处理程序:

float* ptr = nullptr;
float value = *ptr;

上面的代码触发异常处理程序。

我也尝试过使用try/catch或捕捉SIGSEGV信号,但第一个例子都没有触发。中止/终止信号也不会被调用。简而言之,当崩溃发生时,我无法得到通知。

我想知道是否有任何方法可以在我的应用程序中获得某种通知,然后由于第一个示例导致的访问冲突而崩溃?既然VS似乎能够检测到它,我假设有一种方法。

编辑:我只是想说清楚,我是在发布模式下运行代码的,第一个例子中的错误不是由在调试模式下完成的迭代器越界检查引起的。

EDIT2:我列举了我所能想到的使用win32控制台应用的最简单的例子。http://pastebin.com/8L1SN5PQ

确保在没有附加调试器的发布模式下运行。

这类运行时错误的处理方式不同,它们不会产生SEH异常。大致归类在"编程错误"answers"恶意软件攻击"之间。如果您没有附加调试器,则默认处理程序将通过__fastfail()调用即时死亡,这与未捕获的c++异常一样具有信息。

您必须在main()函数中调用_set_invalid_parameter_handler()来更改它们的处理方式。您可以在自定义处理程序中抛出c++异常,或者调用RaiseException()来触发catch-em-all处理程序,或者直接在那里报告它们。如果选择后者,则需要确保进程始终被终止。

请注意,您的代码片段并不是最好的示例。当您在没有启用迭代器调试的情况下构建程序时,就像使用默认设置的Release构建一样,这是UB。UB不保证你会得到一个SEH异常。如果它发生了,那么你必须非常小心地编写异常过滤器,它将在堆锁仍然占用的情况下被调用,因此基本的东西无法工作。最好的方法是用一个命名事件唤醒一个守卫进程。

您看不到异常,因为它是由C运行时内部处理的。具体来说,这是一个边界检查,而不是访问冲突。

在调试器中运行它,我发现它是vector中的第242行:
            _DEBUG_ERROR("vector iterators incompatible");

最终调用_CrtDebugReportW: https://msdn.microsoft.com/en-us/library/8hyw4sy7.aspx

可以用_CrtSetReportMode来控制_CrtDebugReportW的行为。

请注意,这在发布模式下不起作用,因为这些是调试模式的边界检查。