VS2005中SetUnhandledExceptionFilter函数应用
很多软件通过设置自己的异常捕获函数,捕获未处理的异常,生成报告或者日志(例如生成mini-dump文件),达到Release版本下追踪Bug的目的。但是,到了VS2005(即VC8),Microsoft对CRT(C运行时库)的一些与安全相关的代码做了些改动,典型的,例如增加了对缓冲溢出的检查。新CRT版本在出现错误时强制把异常抛给默认的调试器(如果没有配置的话,默认是Dr.Watson),而不再通知应用程序设置的异常捕获函数,这种行为主要在以下三种情况出现。
(1) 调用abort函数,并且设置了_CALL_REPORTFAULT选项(这个选项在Release版本是默认设置的)。
(2) 启用了运行时安全检查选项,并且在软件运行时检查出安全性错误,例如出现缓存溢出。(安全检查选项/GS 默认也是打开的)
(3) 遇到_invalid_parameter错误,而应用程序又没有主动调用
_set_invalid_parameter_handler设置错误捕获函数。
所以结论是,使用VS2005(VC8)编译的程序,许多错误都不能在SetUnhandledExceptionFilter捕获到。这是CRT相对于前面版本的一个比较大的改变,但是很遗憾,Microsoft却没有在相应的文档明确指出。
解决方法
之所以应用程序捕获不到那些异常,原因是因为新版本的CRT实现在异常处理中强制删除所有应用程序先前设置的捕获函数,如下所示:
/* Make sure any filter already in place is deleted. */
SetUnhandledExceptionFilter(NULL);
UnhandledExceptionFilter(&ExceptionPointers);
解决方法是拦截CRT调用SetUnhandledExceptionFilter函数,使之无效。在X86平台下,可以使用以下代码。
#ifndef _M_IX86
#error "The following code only works for x86!"
#endif
void DisableSetUnhandledExceptionFilter()
{
void *addr = (void*)GetProcAddress(LoadLibrary(_T("kernel32.dll")),
"SetUnhandledExceptionFilter");
if (addr)
{
unsigned char code[16];
int size = 0;
code[size++] = 0x33;
code[size++] = 0xC0;
code[size++] = 0xC2;
code[size++] = 0x04;
code[size++] = 0x00;
DWORD dwOldFlag, dwTempFlag;
VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
}
}
在设置自己的异常处理函数后,调用DisableSetUnhandledExceptionFilter禁止CRT设置即可。
其它讨论
上面通过设置api hook,解决了在VS2005上的异常捕获问题,这种虽然不是那么“干净”的解决方案,确是目前唯一简单有效的方式。
虽然也可以通过_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT), signal(SIGABRT, ...),和_set_invalid_parameter_handler(...) 解决(1)(3),但是对于(2),设置api hook是唯一的方式。
VS2005中SetUnhandledExceptionFilter函数应用的更多相关文章
- Qt4.6.2已编译二进制版本在VS2005中的问题
结论1:如果你想把Qt4.6.2安装在VS2005中,又不想花时间编译,请下载和安装qt-win-opensource-4.6.2-vs2008,并单独编译“QT安装路径/src/winmain/” ...
- vc6.0转vs2005中字符串的问题
简单一点:就是project->Property->Configuration Property-->general-->Character Set:No Set即可.详细分析 ...
- 编译器如何处理C++不同类中同名函数(参数类型个数都相同)
转载请注明出处,版权归作者所有 lyzaily@126.com yanzhong.lee 作者按: 从这篇文章中,我们主要会认识到一下几点: 一.不类中的特征标相同的同名函数,它们是不同的函数,原因就 ...
- Oracle 中 decode 函数用法
Oracle 中 decode 函数用法 含义解释:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF 条件=值1 THEN RETURN(翻译 ...
- mysql中now()函数的使用,还有oracle的sysdate,可能埋下的坑
mysql中now()函数的使用,还有oracle的sysdate 在需求中如果系统中药添加当前操作的时间那么很简单的一个操作在写sql的时候直接在这个字段对应的位置写上now()函数就可以了,这样就 ...
- 程序代码中退出函数exit()与返回函数return ()的区别
程序代码中退出函数exit()与返回函数return ()的区别 exit(0):正常运行程序并退出程序: exit(1):非正常运行导致退出程序: return():返回函数,若在主函数 ...
- mysql中find_in_set()函数的使用
首先举个例子来说: 有个文章表里面有个type字段,它存储的是文章类型,有 1头条.2推荐.3热点.4图文等等 .现在有篇文章他既是头条,又是热点,还是图文,type中以 1,3,4 的格式存储.那我 ...
- QT中使用函数指针
想仿命令行,所以定义了一个类,让一个String 对应一个 function,将两者输入list容器. 类中定义了 QString commandStr; void (MainWindow::*com ...
- Bash 是如何从环境变量中导入函数的
在上文中曾说到: 所谓的环境变量的真实面目其实就是个任意字符串 Bash 在启动时会将 environ 数组中包含 = 号的字符串导入成为自己的变量 Bash 在启动外部命令时会将自己内部标记为环境变 ...
随机推荐
- CF下Split的使用
在Compact Framework 下 String的Split不能正确的处理 字符串 分割字符串 如对字符串 "abcfdef12abcedef23" 以"ef&qu ...
- Android项目源码界面超级华丽的仿QQ最新版本
这是一个我们比较熟悉的一款应用,高仿专仿最新QQ应用源码,也是一个高仿QQ最新版本的项目,界面超级华丽,使用了大量的自定义控件,项目里实现了部分功能,例如WIFI-FTP(把手机变成FTP服务端,可以 ...
- oracle视图索引
reate table fleet_header( day date,name varchar2(20), route_id number(5),fleet_id number(5)); crea ...
- 个人实验记录之EIGRP基本配置
一.EIGRP的基本配置 1(1).进入接口配置IP R1(config)#inter s1/0 R1(config-if)#ip address 200.1.1.1 255.255.255.0 R1 ...
- Struts升级到2.3.15.1抵抗漏洞
后知后觉,今天才开始修复Struts2的漏洞 详细情形可以参考: http://struts.apache.org/release/2.3.x/docs/security-bulletins.html ...
- JS面向对象5中写法
//定义Circle类,拥有成员变量r,常量PI和计算面积的成员函数area() //第1种写法 function Circle(r) { this.r = r; } Circle.PI = 3.14 ...
- UVa11384
题意:给定正整数n,求把1,2,--,n中所有书都变成0的最少操作次数,每次操作可从序列中选择一个或多个整数,同时减去一个相同的正整数. 分析:如1,2,3,4,5,6, 第一步将4,5,6同时减4, ...
- Java 学习计划
第一部分 在搭建SSM的过程中,可能会经常接触到一个叫maven的工具.这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识.在你目前这个阶 ...
- [C#]AccessUtils
关键代码: using System; using System.Data; using System.Data.OleDb; namespace CSharpUtilHelpV2 { /// < ...
- aix 安装redis
下载最新rpm安装包 http://www.perzl.org/aix/index.php?n=Main.Redis # uname -aAIX rhjf 1 6 00C5CC964C00# pwd/ ...