场景

1.在Windows上用C/C++开发软件, 经常会出现软件级别的崩溃情况, 如果用户看到这种崩溃报告, 那么一般会认为软件质量不高, 从而不想用. Windows上就会有崩溃报告这种噢给你工具来生成dump文件来分析, 可以让用户发送崩溃报告过来解决问题进而提高软件质量.

2.一般情况下有些崩溃无法捕捉, 这是因为CRT调用SetUnhandledExceptionFilter(0)来移除自定义处理器.

例子

1.以下例子使用了部分[Windows][初级][Release程序的崩溃报告minidump解决方案] 代码. 大多数情况下生成的崩溃报告时需要打包的, 这样方便传输. 这里为了说明主要问题忽略打包部分. CAPIHook部分参考了 SetUnhandledExceptionFilter and the C/C++ Runtime Library.

2.这种方式能捕捉大部分异常和崩溃, 但是有个问题, 就是通过CAPIHook转发的dmp文件不能获取到准确的出错行,(有人知道的话留个言)

3.项目地址在项目源码. 注意, 这个test-crash.cpp项目代码不是最新, 用以下的.[20170103]

  1. // test-crash.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include <SDKDDKVer.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <tchar.h>
  8. #include <Windows.h>
  9. #include <DbgHelp.h>
  10. #include <string>
  11. #include <vector>
  12. #include <iostream>
  13. #include "APIHook.h"
  14. static std::wstring gDumpPath;
  15. static std::wstring gDumpZipPath;
  16. static BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
  17. {
  18. if(pModuleName == NULL)
  19. {
  20. return FALSE;
  21. }
  22. WCHAR szFileName[_MAX_FNAME] = L"";
  23. _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
  24. if(wcscmp(szFileName, L"ntdll") == 0)
  25. return TRUE;
  26. return FALSE;
  27. }
  28. static BOOL CALLBACK MiniDumpCallback(PVOID pParam,
  29. const PMINIDUMP_CALLBACK_INPUT pInput,
  30. PMINIDUMP_CALLBACK_OUTPUT pOutput)
  31. {
  32. if(pInput == 0 || pOutput == 0)
  33. return FALSE;
  34. switch(pInput->CallbackType)
  35. {
  36. case ModuleCallback:
  37. if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
  38. if(!IsDataSectionNeeded(pInput->Module.FullPath))
  39. pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
  40. case IncludeModuleCallback:
  41. case IncludeThreadCallback:
  42. case ThreadCallback:
  43. case ThreadExCallback:
  44. return TRUE;
  45. default:;
  46. }
  47. return FALSE;
  48. }
  49. static LONG WINAPI TopLevelUnhandledExceptionFilter(PEXCEPTION_POINTERS pExInfo)
  50. {
  51. HANDLE hFile = ::CreateFile( gDumpPath.c_str(), GENERIC_WRITE, 0, NULL,
  52. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  53. if( hFile != INVALID_HANDLE_VALUE)
  54. {
  55. MINIDUMP_EXCEPTION_INFORMATION einfo;
  56. einfo.ThreadId = ::GetCurrentThreadId();
  57. einfo.ExceptionPointers = pExInfo;
  58. einfo.ClientPointers = FALSE;
  59. MINIDUMP_CALLBACK_INFORMATION mci;
  60. mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
  61. mci.CallbackParam = NULL;
  62. ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile,MiniDumpNormal,&einfo, NULL, &mci);
  63. ::CloseHandle(hFile);
  64. }
  65. std::cout << "TopLevelUnhandledExceptionFilter" << std::endl;
  66. return EXCEPTION_EXECUTE_HANDLER;
  67. }
  68. static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
  69. LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
  70. {
  71. return NULL;
  72. }
  73. LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
  74. {
  75. std::cout << "VectoredExceptionHandler" << std::endl;
  76. HANDLE hFile = ::CreateFile( gDumpPath.c_str(), GENERIC_WRITE, 0, NULL,
  77. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  78. if( hFile != INVALID_HANDLE_VALUE)
  79. {
  80. MINIDUMP_EXCEPTION_INFORMATION einfo;
  81. einfo.ThreadId = ::GetCurrentThreadId();
  82. einfo.ExceptionPointers = pExceptionInfo;
  83. einfo.ClientPointers = FALSE;
  84. MINIDUMP_CALLBACK_INFORMATION mci;
  85. mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
  86. mci.CallbackParam = NULL;
  87. ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile,MiniDumpNormal,&einfo, NULL, &mci);
  88. ::CloseHandle(hFile);
  89. }
  90. exit(-1);
  91. return EXCEPTION_CONTINUE_EXECUTION ;
  92. }
  93. LONG WINAPI RedirectedSetUnhandledExceptionFilter(EXCEPTION_POINTERS * pExceptionInfo)
  94. {
  95. // When the CRT calls SetUnhandledExceptionFilter with NULL parameter
  96. // our handler will not get removed.
  97. std::cout << "RedirectedSetUnhandledExceptionFilter" << std::endl;
  98. return EXCEPTION_CONTINUE_SEARCH ;
  99. }
  100. const wchar_t* GetAppModule()
  101. {
  102. static wchar_t szbuf[MAX_PATH];
  103. ::GetModuleFileNameW(NULL,szbuf,MAX_PATH);
  104. return szbuf;
  105. }
  106. void TestNULLPointerExceptionCrash()
  107. {
  108. std::cout << "TestNULLPointerExceptionCrash" << std::endl;
  109. int* i = NULL;
  110. *i = 9;
  111. }
  112. void TestRaiseExceptionCrash()
  113. {
  114. std::cout << "TestRaiseExceptionCrash" << std::endl;
  115. RaiseException(0xc0000374, 0, 0, NULL);
  116. }
  117. void TestCorruptCrash()
  118. {
  119. std::cout << "TestCorruptCrash" << std::endl;
  120. std::string* str = new std::string("hello");
  121. delete str;
  122. str->append("worldasdfasdfasdfasdfasdfasdfasdfasdfasdfas");
  123. delete str;
  124. //std::cout << str << std::endl;
  125. }
  126. void TestfreadCrash()
  127. {
  128. std::cout << "TestfreadCrash" << std::endl;
  129. fread("hello",5,1,NULL);
  130. }
  131. void TestAbortCrash()
  132. {
  133. std::cout << "TestAbortCrash" << std::endl;
  134. abort();
  135. }
  136. void TestOutOfBoundsVectorCrash()
  137. {
  138. std::cout << "std::vector out of bounds crash!" << std::endl;
  139. std::vector<int> v;
  140. v[0] = 5;
  141. }
  142. int _tmain(int argc, _TCHAR* argv[])
  143. {
  144. gDumpPath = GetAppModule();
  145. gDumpPath.append(L"-minidump.dmp");
  146. AddVectoredExceptionHandler(1, VectoredExceptionHandler);
  147. SetUnhandledExceptionFilter(TopLevelUnhandledExceptionFilter);
  148. CAPIHook apiHook("kernel32.dll",
  149. "SetUnhandledExceptionFilter",
  150. (PROC)RedirectedSetUnhandledExceptionFilter);
  151. // 第一种 TopLevelUnhandledExceptionFilter
  152. //TestNULLPointerExceptionCrash();
  153. // 第二种 TopLevelUnhandledExceptionFilter
  154. //TestRaiseExceptionCrash();
  155. // 第三种 CAPIHook
  156. // 问题事件名称: BEX
  157. //TestfreadCrash();
  158. // 第四种 AddVectoredExceptionHandler
  159. TestCorruptCrash();
  160. // 第五种 CAPIHook
  161. // 问题事件名称: APPCRASH
  162. //TestAbortCrash();
  163. // 第六种 TopLevelUnhandledExceptionFilter
  164. //TestOutOfBoundsVectorCrash();
  165. std::cout << "End..." << std::endl;
  166. return 0;
  167. }

备注:

EXCEPTION_CONTINUE_EXECUTION (–1) Exception is dismissed. Continue execution at the point where the exception occurred.

EXCEPTION_CONTINUE_SEARCH (0) Exception is not recognized. Continue to search up the stack for a handler, first for containing try-except statements, then for handlers with the next highest precedence.

EXCEPTION_EXECUTE_HANDLER (1) Exception is recognized. Transfer control to the exception handler by executing the __except compound statement, then continue execution after the __except block.

参考

SetUnhandledExceptionFilter and the C/C++ Runtime Library

try-except Statement

[Windows]_[中级]_[崩溃报告的中级解决方案]的更多相关文章

  1. Google Breakpad 在 windows下捕获程序崩溃报告

    http://blog.csdn.net/goforwardtostep/article/details/56304285

  2. [Windows]_[0基础]_[Release程序的崩溃报告minidump解决方式]

    场景: 1. Release的程序崩溃时,崩溃报告能够让开发者查明代码哪里出了问题,用处大大的. 2. 仅仅实用VS的编译器才支持,所以MinGW就无缘了. 3. 使用了未处理异常过滤处理函数. 4. ...

  3. 关于Windows文件读写_暗涌_新浪博客

    关于Windows文件读写_暗涌_新浪博客     这几天在研究怎么才能加快windows文件读写速度,搜了很多文章,MSDN也看了不少.稍微给大家分享一下.     限制windows文件读写速度的 ...

  4. Windows基础环境_安装配置教程(Windows7 64、JDK1.8、Android SDK23.0、TortoiseSVN 1.9.5)

    Windows基础环境_安装配置教程(Windows7 64.JDK1.8.Android SDK23.0.TortoiseSVN 1.9.5) 安装包版本 1)     JDK版本包 地址: htt ...

  5. 看懂 游戏《Minecraft》的崩溃报告 服务端/客户端

    如何看懂Minecraft报错的关键信息. 让你如何看懂Minecraft报错 前言 一些俏皮话 寻找崩溃日志 打开崩溃日志 重要的事说三遍 下载文本编辑器 开始分析 深度分析 得出结论 修复报错 解 ...

  6. 宏定义中的##操作符和... and _ _VA_ARGS_ _

    1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operator, the ## operator can be used i ...

  7. Lock锁_线程_线程域

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  8. C++框架_之Qt的开始部分_概述_安装_创建项目_快捷键等一系列注意细节

    C++框架_之Qt的开始部分_概述_安装_创建项目_快捷键等一系列注意细节 1.Qt概述 1.1 什么是Qt Qt是一个跨平台的C++图形用户界面应用程序框架.它为应用程序开发者提供建立艺术级图形界面 ...

  9. 软件测试_Loadrunner_APP测试_性能测试_脚本优化_脚本回放

    本文主要写一下在使用Loadrunner录制完毕APP脚本之后如何对脚本进行回放,如有不足,欢迎评论补充. 如没有安装Loadrunner软件,请查看链接:软件测试_测试工具_LoadRunner: ...

随机推荐

  1. tomcat idea optinos

    -server -XX:PermSize=128M -XX:MaxPermSize=256m -Xms512m -Xmx1024m

  2. [翻译] GCDObjC

    GCDObjC https://github.com/mjmsmith/gcdobjc GCDObjC is an Objective-C wrapper for the most commonly ...

  3. [C++] 用Xcode来写C++程序[2] 操作变量

    用Xcode来写C++程序[2] 操作变量 此节讲解包括变量的初始化的几种方式,以及泛型编程的两种变量赋值方式. 最基本的变量赋值以及操作: // operating with variables # ...

  4. iOS8中的定位服务

    iOS8中的定位服务 My app that worked fine in iOS 7 doesn't work with the iOS 8 SDK. CLLocationManager doesn ...

  5. Imagex用法

    imagex用来合并/导出wim映像实例 查看wim中包含的所有单个wim实例信息,注意其中的index是唯一的,用来区分不同的wim,导出的时候也通过该index导出相应的wimimagex /in ...

  6. sharepoint 2013 sp1 patch安装后的手工运行

    在安装SP1 后,有时Center admin 会显示 那么必须在以administrator运行sharepoint 2013 powershell. PSConfig.exe -cmd upgra ...

  7. September 17th 2017 Week 38th Sunday

    Distance could make you forget about them, but the memories would always be there. 距离会让你遗忘,但是回忆却始终在那 ...

  8. ubuntu配置默认python版本并安装pip

    ubuntu 16.04本身是自带python的,他本身是自带2.X和3.X,两个版本,默认的是2.X.这里记录一下如果在版本间切换以及如何把python版本切换到3.X下的方法. 1.查看Ubunt ...

  9. SICP 习题 (1.34)解题总结

    SICP 习题 1.34的题目比較特别一点.对于没有接触过高阶函数的同学们来说是个非常好的学习机会. 题目是这种,假设我们定义以下的过程: (define (f g)   (g 2)) 那么就有: ( ...

  10. Spring-IOC 在非 web 环境下优雅关闭容器

    当我们设计一个程序时,依赖了Spring容器,然而并不需要spring的web环境时(Spring web环境已经提供了优雅关闭),即程序启动只需要启动Spring ApplicationContex ...