在 Windows 上捕获访问冲突 [英] Catching access violations on Windows

查看:26
本文介绍了在 Windows 上捕获访问冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to catch all unhandled exceptions in my application so I can save a log file when they occurr. This is a 64-bit Windows application compiled using Visual Studio 2013, written in C++. For testing I am using the default C++ Win32 project generated by VS.

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

I am catching all exceptions by registering a handler using SetUnhandledExceptionFilter. This works fine for /most/ cases, but not all. All throw()-n exceptions are caught, and most hardware exceptions like floating point or access violations as well. The code that doesn't trigger the handler is:

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

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

Instead I just get the standard windows crash dialog box, without my exception handler getting called. If I run it in Visual Studio with debugger attached however, it correctly reports an access violation exception. Other types of access violations trigger the handler as well:

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

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

Code above triggers the exception handler.

我也尝试过使用 try/catch 或捕获 SIGSEGV 信号,但都没有被第一个示例触发.也不会调用中止/终止信号.简而言之,我不会在崩溃发生时收到任何通知.

I have tried using try/catch or catching SIGSEGV signal too, but neither get triggered with the first example. abort/terminate signals don't get called either. In short I am in no way notified when that crash happens.

我想知道有没有什么办法可以在我的应用程序由于第一个示例引起的访问冲突而崩溃之前在我的应用程序中获得某种通知?由于 VS 似乎能够检测到它,我假设有一种方法.

I want to know is there any way I can get some kind of a notification in my application before it crashes due to the access violation caused by the first example? Since VS seems to be able to detect it I'm assuming there's a way.

我只想说明我在发布模式下运行代码,第一个示例中的错误不是由在调试模式下完成的迭代器越界检查引起的.

I just want to make it clear I'm running the code in release mode and the error in the first example isn't caused by iterator out of bounds check done in debug mode.

我包含了我可以使用 win32 控制台应用程序想出的最简单示例.在这里看到它:http://pastebin.com/8L1SN5PQ

I included the simplest example I can come up with using a win32 console app. See it here: http://pastebin.com/8L1SN5PQ

确保在没有附加调试器的情况下在发布模式下运行它.

Make sure to run it in release mode with no debugger attached.

推荐答案

这些类型的运行时错误的处理方式不同,它们不会产生 SEH 异常.大致分类在编程错误"和恶意软件攻击"之间.如果您没有附加调试器,那么与未捕获的 C++ 异常一样信息丰富,默认处理程序使用 __fastfail() 调用立即死亡.

These kind of runtime errors are handled differently, they don't produce an SEH exception. Roughly classified somewhere between "programming bug" and "malware attack". And about as informative as a uncaught C++ exception if you don't have a debugger attached, the default handler invokes instant death with __fastfail().

您必须在主程序中调用 _set_invalid_parameter_handler()() 函数来改变它们的处理方式.您可以在自定义处理程序中抛出 C++ 异常或调用 RaiseException() 来触发您的 catch-em-all 处理程序,或者直接在那里报告它们.倾向于后者,你要保证进程总是被终止.

You'll have to call _set_invalid_parameter_handler() in your main() function to alter the way they are handled. You could throw a C++ exception in your custom handler or call RaiseException() to trigger your catch-em-all handler or just report them right there. Favor the latter, you want to ensure that the process is always terminated.

请注意,您的代码段不是最好的示例.当您在未启用迭代器调试的情况下构建程序时,这是 UB,例如具有默认设置的 Release 构建.UB 不保证您会得到 SEH 例外.如果确实如此,那么您必须非常小心地编写异常过滤器,它将在仍然采用堆锁的情况下调用它,因此基本的东西无法工作.最好的方法是使用命名事件唤醒守卫进程.然后进行小型转储并终止程序.

Do beware that your snippet is not the best possible example. This is UB when you build your program without iterator debugging enabled, like the Release build with default settings. UB does not guarantee you'll get an SEH exception. And if it does then you'll have to write your exception filter very carefully, it will be called with the heap lock still taken so basic stuff cannot work. Best way is to wakeup a guard process with a named event. Which then takes a minidump and terminates the program.

这篇关于在 Windows 上捕获访问冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆