快速业务通道

Win32结构化异常处理(SEH)探秘(上)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
程序拒绝处理某个异常时,它实际上也就拒绝决定流程最终将从何处恢复。只有接受某个异常的异常处理程序才能决定待所有异常处理代码执行完毕之后流程将从何处继续执行。这个规则暗含的意义非常重大,虽然现在还不是显而易见。

当使用结构化异常处理时,如果一个函数有一个异常处理程序但它却不处理某个异常,这个函数就有可能非正常退出。例如在 MYSEH2中 HomeGrownFrame 函数就不处理异常。由于在链表中后面的某个异常处理程序(这里是 main 函数中的)处理了这个异常,因此出错指令后面的 printf 就永远不会执行。从某种程度上说,使用结构化异常处理与使用 setjmp 和 longjmp 运行时库函数有些类似。

如果你运行 MYSEH2,会发现其输出有些奇怪。看起来好像调用了两次 _except_handler 函数。根据你现有的知识,第一次调用当然可以完全理解。但是为什么会有第二次呢?

Home Grown handler: Exception Code: C0000005 Exception Flags 0
Home Grown handler: Exception Code: C0000027 Exception Flags 2 EH_UNWINDING
Caught the Exception in main()

比较一下以“Home Grown Handler”开头的两行,就会看出它们之间有明显的区别。第一次异常标志是0,而第二次是2。这个问题说来话就长了。实际上,当一个异常处理回调函数拒绝处理某个异常时,它会被再一次调用。但是这次回调并不是立即发生的。这有点复杂。我需要把异常发生时的情形好好梳理一下。

当异常发生时,系统遍历 EXCEPTION_REGISTRATION 结构链表,直到它找到一个处理这个异常的处理程序。一旦找到,系统就再次遍历这个链表,直到处理这个异常的结点为止。在这第二次遍历中,系统将再次调用每个异常处理函数。关键的区别是,在第二次调用中,异常标志被设置为2。这个值被定义为 EH_UNWINDING。(EH_UNWINDING 的定义在 Visual C++ 运行时库源代码文件 EXCEPT.INC 中,但 Win32 SDK 中并没有与之等价的定义。)

EH_UNWINDING 表示什么意思呢?原来,当一个异常处理回调函数被第二次调用时(带 EH_UNWINDING 标志),操作系统给这个函数一个最后清理的机会。什么样的清理呢?一个绝好的例子是 C++ 类的析构函数。当一个函数的异常处理程序拒绝处理某个异常时,通常执行流程并不会正常地从那个函数退出。现在,想像一下定义了一个C++类的实例作为局部变量的函数。C++规范规定析构函数必须被调用。这带 EH_UNWINDING 标志的第二次回调就给这个函数一个机会去做一些类似于调用析构函数和__finally 块之类的清理工作。

在异常已经被处理完毕,并且所有前面的异常帧都已经被展开之后,流程从处理异常的那个回调函数决定的地方开始继续执行。一定要记住,仅仅把指令指针设置到所需的代码处就开始执行是不行的。流程恢复执行处的代码的堆栈指针和栈帧指针(在Intel CPU上是 ESP 和EBP)也必须被恢复成它们在处理这个异常的函数的栈帧上的值。因此,这个处理异常的回调函数必须负责把堆栈指针和栈帧指针恢复成它们在包含处理这个异常的 SEH 代码的函数的堆栈上的值。

通常,展开操作导致堆栈上处理异常的帧以下的堆栈区域上的所有内容都被移除了,就好像我们从来没有调用过这些函数一样。展开的另外一个效果就是 EXCEPTION_REGISTRATION 结构链表上处理异常的那个结构之前的所有 EXCEPTION_REGISTRATION 结构都被移除了。这很好理解,因为这些 EXCEPTION_REGISTRATION 结构通常都被创建在堆栈上。在异常被处理后,堆栈指针和栈帧指针在内存中比那些从 EXCEPTION_REGISTRATION 结构链表上移除的 EXCEPTION_REGISTRATION 结构高。图六显示了我说的情况。

图六 从异常展开

帮帮我!没有人处理它!

迄今为止,我实际上一直在假设操作系统总是能在

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号