简体   繁体   English

在Windows上捕获访问冲突

[英]Catching access violations on Windows

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++. 这是一个使用Visual Studio 2013编译的64位Windows应用程序,用C ++编写。 For testing I am using the default C++ Win32 project generated by VS. 为了测试我使用VS生成的默认C ++ Win32项目。

I am catching all exceptions by registering a handler using SetUnhandledExceptionFilter. 我通过使用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. 捕获所有throw() - n异常,以及大多数硬件异常,例如浮点或访问冲突。 The code that doesn't trigger the handler is: 不触发处理程序的代码是:

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

Instead I just get the standard windows crash dialog box, without my exception handler getting called. 相反,我只是获得标准的Windows崩溃对话框,而不会调用异常处理程序。 If I run it in Visual Studio with debugger attached however, it correctly reports an access violation exception. 但是,如果我在附带调试器的Visual Studio中运行它,它会正确报告访问冲突异常。 Other types of access violations trigger the handler as well: 其他类型的访问冲突也会触发处理程序:

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

Code above triggers the exception handler. 上面的代码触发异常处理程序。

I have tried using try/catch or catching SIGSEGV signal too, but neither get triggered with the first example. 我也尝试过使用try / catch或捕获SIGSEGV信号,但是第一个例子都没有触发。 abort/terminate signals don't get called either. 中止/终止信号也不会被调用。 In short I am in no way notified when that crash happens. 简而言之,当崩溃发生时,我不会得到通知。

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. 由于VS似乎能够检测到它,我假设有一种方法。

EDIT: 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. 编辑:我只想说明我在发布模式下运行代码,第一个示例中的错误不是由调试模式下的迭代器超出边界检查引起的。

EDIT2: I included the simplest example I can come up with using a win32 console app. EDIT2:我包含了一个最简单的例子,我可以使用win32控制台应用程序。 See it here: http://pastebin.com/8L1SN5PQ 请在此处查看: http//pastebin.com/8L1SN5PQ

Make sure to run it in release mode with no debugger attached. 确保在没有附加调试器的发布模式下运行它。

These kind of runtime errors are handled differently, they don't produce an SEH exception. 这些运行时错误的处理方式不同,它们不会产生SEH异常。 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(). 如果您没有附加调试器,那么就像未被捕获的C ++异常一样提供信息,默认处理程序使用__fastfail()调用即时死亡。

You'll have to call _set_invalid_parameter_handler() in your main() function to alter the way they are handled. 您必须在main()函数中调用_set_invalid_parameter_handler()来改变它们的处理方式。 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. 您可以在自定义处理程序中抛出C ++异常,或者调用RaiseException()来触发catch-em-all处理程序或只是在那里报告它们。 Favor the latter, you want to ensure that the process is always terminated. 支持后者,您希望确保始终终止该过程。

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,例如使用默认设置的发布版本。 UB does not guarantee you'll get an SEH exception. UB不保证您会收到SEH例外。 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. 然后采用minidump并终止程序。

You are not seeing the exception because it is being handled internally by the C runtime. 您没有看到异常,因为它是由C运行时内部处理的。 Specifically it's a bounds check not an access violation. 具体来说,它是一个边界检查而不是访问冲突。

Running it up in the debugger I find that it is line 242 in vector : 在调试器中运行它我发现它是vector第242行:

            _DEBUG_ERROR("vector iterators incompatible");

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

You can control the behaviour of _CrtDebugReportW using _CrtSetReportMode . 您可以使用_CrtSetReportMode控制_CrtDebugReportW的行为。

Note that this has no effect in release mode as these are debug-mode bounds checks. 请注意,这在发布模式下没有任何影响,因为这些是调试模式边界检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM