简体   繁体   English

为什么我的 UnhandledExceptionFilter 没有被简单地除以零调用?

[英]Why is my UnhandledExceptionFilter not being called on a simple divide by zero?

I am using the following MSVC++ console application code (running on Windows 8.1, Release, Win32) to try and return a top-level exception back to me:我正在使用以下 MSVC++ 控制台应用程序代码(在 Windows 8.1、Release、Win32 上运行)尝试将顶级异常返回给我:

#include "stdafx.h"
#include <Windows.h>
#include <iostream>

using namespace std; 

LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS exception)
{
    printf("Got an unhandled exception.");
    return EXCEPTION_CONTINUE_SEARCH;
}

int _tmain(int argc, _TCHAR* argv[])
{
    SetUnhandledExceptionFilter(UnhandledExceptionFilter);
    int a = 0;
    int b = 0;
    int c = a / b;
    cin.get();
    return 0;
}

My UnhandledExceptionFilter doesn't actually seem to ever get called on the divide by zero exception that is being thrown in this example, otherwise I would expect the "Got an unhandled exception" log message to show up.我的UnhandledExceptionFilter实际上似乎从未在本示例中抛出的除以零异常时被调用,否则我希望显示“有一个未处理的异常”日志消息。 Why is that?这是为什么?

Integer division by zero is undefined behavior.整数除以零是未定义的行为。 If an implementation choose to raise an exception for that (or for any other undefined behavior), that's fine.如果实现选择为此(或任何其他未定义的行为)引发异常,那很好。 If an implementation chooses not to raise an exception for some undefined behavior, that's also fine.如果实现选择为某些未定义的行为引发异常,那也没关系。 Whatever the implementation does when confronted with undefined behavior is fine.无论实现在遇到未定义的行为时做什么都很好。 It's not their problem.这不是他们的问题。

Apparently MSVC++ running on Windows 8.1, Win32 doesn't raise an exception on division by zero.显然 MSVC++ 在 Windows 8.1 上运行,Win32 不会在除以零时引发异常。

You should never expect undefined behavior to result in something expected.您永远不应该期望未定义的行为会导致预期的结果。

The function specified by SetUnhandledExceptionFilter() won't be called if the application is running under a debugger, the idea being that SetUnhandledExceptionFilter() should only be used to generate a crash dump and then exit an application.如果应用程序在调试器下运行,则不会调用由 SetUnhandledExceptionFilter() 指定的函数,其想法是 SetUnhandledExceptionFilter() 应仅用于生成故障转储然后退出应用程序。 This isn't very useful if you have a debugger attached, so the debugger will handle the exception first.如果您附加了调试器,这不是很有用,因此调试器将首先处理异常。

The MSDN documentation references this: MSDN 文档引用了这个:

After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.调用该函数后,如果一个未被调试的进程发生异常,并且该异常进入未处理异常过滤器,该过滤器将调用lpTopLevelExceptionFilter参数指定的异常过滤器函数。

Divide By Zero is actually a CPU trap, more than an exception as in programming sense.除以零实际上是一个 CPU 陷阱,不仅仅是编程意义上的异常。 You should define a trap handler instead of an exception handler.您应该定义陷阱处理程序而不是异常处理程序。

It looks to me like the exceptions isn't actually a true unhandled exception from the OS perspective.在我看来,从操作系统的角度来看,异常实际上并不是真正的未处理异常。 You're calling printf , so you have linked in the CRT.您正在调用printf ,因此您已在 CRT 中进行了链接。 IIRC, the CRT handles exceptions escaping from main , but from the OS viewpoint an unhandled exception is one that escapes the true entry point - ie the CRT function which calls main. IIRC,CRT 处理从main转义的异常,但从操作系统的角度来看,未处理的异常是转义真正入口点的异常——即调用 main 的 CRT 函数。

I believe you actually want a Vectored Exception Handler.我相信你真的想要一个向量异常处理程序。

  1. as @zhenguoli says, UnhandledExceptionFilter is defined in kernel32.lib so it will not link.正如@zhenguoli 所说, UnhandledExceptionFilter是在kernel32.lib定义的,因此它不会链接。 You need to name your exception filter something else.您需要将异常过滤器命名为其他名称。 UnhandledExceptionFilter is what calls your exception Handler set by SetUnhandledExceptionFilter . UnhandledExceptionFilter是调用由SetUnhandledExceptionFilter设置的异常处理程序。

  2. @DavidHammen is unclear because div by zero is indeed handled with exception vector 0 on x86 and GetExceptionCode() would return EXCEPTION_INT_DIVIDE_BY_ZERO . @DavidHammen 不清楚,因为 div 为零确实在 x86 上使用异常向量 0 处理,并且GetExceptionCode()将返回EXCEPTION_INT_DIVIDE_BY_ZERO But, as @davidbak says, in the OP's example compiler does not allow this as the variable c isn't used and will be optimised out.但是,正如@davidbak 所说,在 OP 的示例中,编译器不允许这样做,因为未使用变量 c 并将对其进行优化。 If c were used, then the exception handler at vector 0 would start unwinding the stack and eventually call UnhandledExceptionFilter as a filter expression which is wrapped around the thread entry function in RtlUserThreadStart , which will then call your handler (the thread is started with RtlUserThreadStart as the entry function with the real thread entry function as a parameter).如果使用了 c,则向量 0 处的异常处理程序将开始展开堆栈并最终调用UnhandledExceptionFilter作为过滤器表达式,该表达式包含在RtlUserThreadStart的线程入口函数RtlUserThreadStart ,然后将调用您的处理程序(线程以RtlUserThreadStart启动为以真正的线程入口函数为参数的入口函数)。 The .exe entry function will initialise the CRT and then call main . .exe入口函数将初始化 CRT,然后调用main You are right to use SEH because divbyzero can't be caught by C++ exception handling , which only responds to throw .您使用 SEH 是正确的,因为 divbyzero不能被 C++ 异常处理捕获,它只响应throw

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

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