前段程序测试中使用了SetUnhandledExceptionFilter,发现很多崩溃并没有拦截到,还是弹出关闭窗口,网上找了找,发现问题在于MS在c++缓存溢出检查中重置了这个函数,原因很简单,避免黑客利用这个常见错误黑电脑,不过也带来很多不便,这篇文章告诉我们如何避开这个问题

SetUnhandledExceptionFilter and VC

原文: http://blog.kalmbachnet.de/?postid=75

Many programs are setting an own Unhandled-Exception-Filter , for catching unhandled exceptions and do some reporting or logging (for example creating a mini-dump ).

Now, starting with VC8 (VS2005), MS changed the behaviour of the CRT is some security related and special situations.
The CRT forces the call of the default-debugger (normally Dr.Watson) without informing the registered unhandled exception filter. The situations in which this happens are the following:

So the conclusion is: The are many situations in which your user-defined Unhandled-Exception-Filter will never be called. This is a major change to the previous versions of the CRT and IMHO not very well documented.

The solution

If you don’t want this behavior and you will be sure that your handler will be called, you need to intercept the call to SetUnhandledExceptionFilter which is used by the CRT to disable all previously installed filters. You can achieve this for x86 with the following code:

  #include <windows.h>
  #include <tchar.h>
  #include <stdio.h>
  #ifndef _M_IX86
  #error "The following code only works for x86!"
  #endif
  LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
    LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
    return NULL;
  BOOL PreventSetUnhandledExceptionFilter()
    HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
    if (hKernel32  NULL) return FALSE;
    void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
    if(pOrgEntry  NULL) return FALSE;
    unsigned char newJump[ 100 ];
    DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
    dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
    void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
    DWORD dwNewEntryAddr = (DWORD) pNewFunc;
    DWORD dwRelativeAddr = dwNewEntryAddr – dwOrgEntryAddr;
    newJump[ 0 ] = 0xE9;  // JMP absolute
    memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
    SIZE_T bytesWritten;
    BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
      pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
    return bRet;
  LONG WINAPI MyUnhandledExceptionFilter(
    struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter)
    // TODO: MiniDumpWriteDump
    FatalAppExit(0, _T(“Unhandled Exception occured!”));
    return EXCEPTION_CONTINUE_SEARCH;
  int _tmain()
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
    BOOL bRet = PreventSetUnhandledExceptionFilter();
    _tprintf(_T(“Prevented: %d”), bRet);
    abort();  // force Dr.Watson in release!

Before calling PreventSetUnhandledExceptionFilter you must be sure that no other thread is running (or at least no other thread is trying to callSetUnhandledExceptionFilter).

前段程序测试中使用了SetUnhandledExceptionFilter,发现很多崩溃并没有拦截到,还是弹出关闭窗口,网上找了找,发现问题在于MS在c++缓存溢出检查中重置了这个函数,原因很简单,避免黑客利用这个常见错误黑电脑,不过也带来很多不便,这篇文章告诉我们如何避开这个问题SetUnhandledExceptionFilter and VC原文:http://blog.kalmba
崩溃转储 演示如何使C进程(crasher.exe)崩溃时进行堆栈跟踪和小型转储。 两者都由另一个进程(dumper.exe)完成,这对于使用可靠的堆栈跟踪进行转储至关重要。 崩溃器使用SetUnhandledExceptionFilter注册异常处理程序。 该处理程序启动转储程序并等待其退出。 它在命令行中将其进程ID,线程ID和异常指针(包含上下文记录)传递给转储程序。 异常指针非常有用,因为它包含原始异常的上下文,而不是当前上下文(在异常处理程序内部)。 然后,崩溃程序等待自卸车完成(但请参见下面的其他1)。 启动时,dumper使用其命令行中的进程和线程ID打开崩溃程序的句柄。 然后,它使用对ReadProcessMemory的一些调用来获取转储程序的异常指针和上下文记录。 然后,它将使用此上下文记录来设置原始堆栈帧,并开始使用StackWalk64遍历堆栈。 它还使用Sym
程序在debug可以正常运行,但是在release版后异常结束,系统又没有提供任何信息情况下,或者程序发布后在客户手中出现异常崩溃,但自己测试又不能复现问题,要是能捕获到异常时相关信息就很好定位问题了。 资源中包含Qt mingw编译程序crash信息捕捉和跟踪方法说明,以及测试程序代码。 修改地方 1.*pro 文件添加调试信息;2.添加ccrashstack类,3,main 添加 SetUnhandledExceptionFilter(callback); 4,生成exe指应汇编代码objdump -S xxx.exe >aaa.asm;5,从生成的crash.log得到异常地址查代码
SetUnhandledExceptionFilter 可以注册一个异常处理函数,当一个异常产生且我们的 try - catch(或 try - expect)没有处理处理这个异常时,异常会转交给 SetUnhandledExceptionFilter ,这是我们的应用程序处理异常的最后机会。 我们可以自己触发一个异常,然后不在 try-catch 中处理它,如果存在调试器则调试器就会接管这个异常,那么这个异常就不会走到我们的 SetUnhandledExceptionFilter 注册的异常处理
昨天看了同事的程序,发现解决崩溃弹窗问题的方法很不错,上网搜了一下,也基本都是这个方法,以前确实没怎么关注过这个问题,测试了一下,把出现问题的源代码准确的定位了出来。 1、同事对其进行了封装,封装类如下: #pragma once #include &lt;windows.h&gt; #include &lt;imagehlp.h&gt; #include &lt;stdlib.h&gt;...
SetUnhandledExceptionFilter 很多情况下会有无效的情况. 所以使用 seh 很多,但今天偶然发现了 vs2008 的crt版本也是引起这种情况的原因之一.     char s[9];    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );//没用    _CrtSetReportMode( _CRT_ASSERT...
// 异常处理函数 LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { // 生成dump文件的路径和名称 const char* filePath = "C:\\dump\\myapp.dmp"; // 创建dump文件 HANDLE hFile = CreateFileA(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { // 写入dump文件头部 MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; exceptionInfo.ThreadId = GetCurrentThreadId(); exceptionInfo.ExceptionPointers = ExceptionInfo; exceptionInfo.ClientPointers = FALSE; // 写入dump文件内容 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &exceptionInfo, NULL, NULL); // 关闭dump文件 CloseHandle(hFile); // 继续执行程序 return EXCEPTION_CONTINUE_EXECUTION; 以上代码会在程序发生异常时生成一个名为“myapp.dmp”的dump文件,路径为“C:\dump\”。你可以根据需要修改dump文件的名称和路径。注意,如果程序没有发生异常,dump文件不会生成。 另外,如果你使用的是Visual Studio,可以在项目属性的“Debugging”选项卡中设置生成dump文件的路径和名称。这样,在程序发生异常时,Visual Studio会自动生成dump文件。