当前位置:文档之家› Windows异常处理机制研究

Windows异常处理机制研究

Windows异常处理机制研究
摘要:对Windows异常处理机制的原理进行介绍分析,引入Windows 精髓SEH,并详细介绍了SEH原理,对如何更好地利用SEH服务于代码的编写,并且利用SEH和dump文件进行bug定位进行了研究。

关键词:Windows异常处理机制;SEH;dump文件;bug定位
0 引言
异常处理是一种允许两个独立开发的程序组件在程序执行期间遇到不正常情况下进行相互通信的机制。

包括3步:产生、抛出、处理。

异常广义上可以分为软件异常(software exception)、硬件异常(hardware exception)。

硬件异常也叫CPU异常,比如,程序员不会去存取一个无效的内存地址或用0来除一个数值,不过,这样的错误还是常常会发生的。

C P U负责捕捉无效内存访问和用0除一个数值这种错误,并相应引发一个异常作为对这些错误的反应。

操作系统和应用程序也可以引发相应的异常,即软件异常。

作为时下最流行的系统,Windows SEH在异常的处理上给我们带了非常多的惊喜。

它在程序的稳定和健壮方面发挥着举重轻重的作用。

本文将从代码编写、bug定位方面介绍SEH。

首先对SEH、dump文件进行介绍。

1 SEH和dump文件
1.1 SEH
在C语言的开发过程中,常常会对一个指针进行无休止的检测,对内存的分配是否成功进行繁琐的检测和处理,对C语言测试程序员来说,这是一个十分头疼的事情。

检测机制这么多就是为了同一个目标,即程序的安全性。

但这是一把双刃剑,安全性得到了保证,代码就会显得十分冗余,对阅读方面会造成极大的影响。

指针是C语言的精髓,试想如果一个工程里面通篇都是对不同类型指针安全性进行检测,代码会是怎样一种情况。

SEH的引入就很好地解决了这个难题。

同时,你是否也在为bug定位苦恼。

很多时候,C++的异常处理机制可以很好地跳过异常代码,但是这又同样引入一个问题,虽程序运行没有问题,但是异常终归是异常,必须解决,普通的C++异常无法定位。

SEH的引入同样很好地解决了这个难题。

SEH其英文全称是Structure Exception Handler,即异常处理结构体。

SEH早期的引入是为了方便windows系统的开发,操作系统的开发人员使用SEH,使得系统更加强大。

我们也可以使用SEH,使我们自己的程序更加强大。

使用SEH所造成的负担主要由编译程序来承担,而不是由操作系统承担。

当异常块(exception block)出现时,编译程序要生成特殊的代码。

编译程序必须产生一些表(table)来支持处理SEH的数据结构。

编译程序还必须提供回调(callback)函数,操作系统可以调用这些函数,保证异常块被处理。

编译程序还要负责准备栈结构和其它内部信息,供操作系统使用和参考。

SEH包含两个功能:结束处理、异常处理。

结束异常,需要注意一点。

在_try块中不管以何种方式退出,最后都要进入到_finally块中,程序员需要注意在逻辑的编写过程中,什么应该放在_try块中,什么应该放在_finally块中。

异常处理,这是最值得注意的一点。

在_try块抛出异常之后,怎样在_except块中处理抛出的异常。

这里介绍Windows主要的3个枚举值,2个接口函数。

在_except块中有3个值分别代表3种不同的处理方式。

EXCEPTION_EXECUTE_HANDLER:表示已经识别了抛出的异常,做出相应的处理。

EXCEPTION_CONTINUE_EXECUTION:忽略掉这个异常,直接执行下步。

EXCEPTION_CONTINUE_SEARCH:在这一层中没有识别这个异常,需要再次向上搜索可以处理的_excpet块。

DWORD GetExceptionCode():可以返回系统抛出的异常类型。

在系统底层定义了不同的值代表不同的异常类型。

如EXCEPTION_STACK_OVERFLOW,线程用完了分配给它的所有栈空间。

PEXCEPTION_POINTERS GetExceptionInformation();这个函数返回的是以下这个结构:
typedef struct _EXCEPTION_POINTERS
{
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS,*PEXCEPTION_POINTERS;
EXCEPTION_RECORD结构包含有关已发生异常的独立于CPU 的信息,CONTEXT结构包含已发生异常的依赖CPU的信息。

这个返回值信息非常有用,可以用来生成dump文件,从而可以方便程序员定位程序bug所在位置。

1.2 dump文件
Dump文件是进程的内存镜像。

可以把程序的执行状态通过调试器保存到dump文件中。

这里介绍一个API函数:
BOOL WINAPI MiniDumpWriteDump(
_In_ HANDLE hProcess,
_In_ DWORD ProcessId,
_In_ HANDLE hFile,
_In_ MINIDUMP_TYPE DumpType,_In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
_In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
_In_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam );
这个函数可以根据接收到的PEXCEPTION_POINTERS信息生成
相应的带调试信息的dump文件。

2 代码的规范性
SEH代表的是一种编程的思想,一种编程的理念,遵守产生、抛出、处理机制,遵守这个机制会给整个代码带来一种赏心悦目的感觉。

尤其对于大型项目的联调和扩展尤为重要,能够在真正写的时候达到事半功倍的效果。

3 bug定位
举一个例子,对一个虚地址进行读或写,但没有做适当的存取。

首先在_try块中抛出一个异常,异常的返回类型为EXCEPTION_ACCESS_VIOLATION。

此时将在_except括号中接受到此时产生异常的CPU信息。

通过GetExceptionInformation()函数记录此时的异常,再把此时的异常信息通过MiniDumpWriteDump()函数导入成dump文件。

此时就能很好地定位bug产生的地点。

以下附上这个例子的伪代码:
_try
{
非法访问
}
_except(WriteDumpFile(GetExceptionInformation()),EXCEPTION_EXECUTE_HANDLER )
{
}
WriteDumpFile()函数以传入的执行期间的堆栈为基准,里面通过MiniDumpWriteDump()函数生成可定位的dump文件。

4 结语
异常处理是一种广为使用的系统机制,本文介绍了SEH原理、SEH的代码规范,以及SEH和dump文件一起使用的例子。

但是SEH 的真正用处远不止这些,SEH 在软件安全方面也作出了重大贡献。

参考文献:
[1] 李建忠.异常处理[J].计算机世界,2002(21).
[2] 张文升,刘万军,王静中的异常处理[J].中国数据通信,2005(5).
[3] 黄超.Windows网络编程[M].北京:人民邮电出版社,2003.
[4] 黄陇,RICHTER JEFFREY,NASARR CHRISTOPHE.Windows核心编程[M].北京:机械工业出版社,2008.。

相关主题