`
yangyou230
  • 浏览: 1650202 次
文章分类
社区版块
存档分类

VEH中的陷阱

 
阅读更多

最初发在QQ空间,转到这:http://user.qzone.qq.com/31731705/blog/1314257137

前面从理论(VEH中的陷阱(上))和实际(VEH中的陷阱(下))研究了VEH中存在的问题,那么,VEH的使用过程中有哪些注意事项?

1. 防御性编程

如果异常的目的是和调试器通信,首先应该检测调试器的存在。并且即使调试器存在的情况下,也必须使用SEH去处理自己抛出的异常,不能去指望调试器一定会处理这个异常。代码类似这样,

只有调试器存在的情况下抛出异常,并且使用SEH去处理之,两只手都要硬。OutputDebugString有SEH块,但没有检测调试器的存在。如果它这样做了,之前的程序将会是完成不同的两个结果。

再说一个初始断点的例子。OS在启动应用程序时,在有调试器的情况下会启动初始断点,xp系统做了检测调试器的逻辑,不过却漏了__except块,如果调试器没有处理这个初始断点,应用程序就crash了。听起来不可思议,自己抛出的异常指望别人一定会收拾。但这就是残酷的事实。幸运的是,win7系统下做了修正,初始断点的逻辑中添加了SEH块。(关于初始断点的例子可以参见:http://bbs.pediy.com/showthread.php?t=137703

2. VEH的代码应该如何写呢?

防御性编程在VEH中的作用有限,以上面的代码为例,即使调试器在运行,应用程序抛出的异常也没法指望调试器一定会去处理。而且,VEH存在的情况下SEH无法在第一时间起作用。那么到底如何使用VEH?

最好的办法是不使用它,象我前面说的,VEH是个新东西,原有的大量代码使用SEH,而VEH的出现打破了平衡,太危险,你不知道OS里的代码什么时候会来点问题,象OutputDebugString那样。看看Windows平台下的异常处理浅谈SEH和UEF,你真的需要使用VEH嘛?

如果实在要用,应该这样:只处理你想处理的异常,其它的返回EXCEPTION_CONTINUE_SEARCH,让以前的机制工作。

将OutputDebugString移动到除0异常的代码里(这是你真正想要处理的异常),其它的直接返回。虽然VEH还是会捕捉到OutputDebugString的异常,但它会继续分发下去。代码的执行结果如下:

This is 0, 12f9ac
Exceuting VEH: code=C0000094, flags=0
This is 1, 12ea38
Exceuting VEH: code=40010006, flags=0
This is 2, 12f6dc
Exceuting VEH: code=40010006, flags=0
exit VEH

通过只处理自己需要处理的异常,继续分发其它的异常,可以一定程序上保证VEH的安全,也保证了VEH和SEH之间的兼容性。但即使如此,VEH就象一座活火山一样,你不知道它什么时候会爆发。

3. VEH能否构造自己的平衡?

现存的大量代码都是基于SEH,VEH的横空出世破坏了现有的格局,有没有办法象SEH那样嵌套的使用VEH?

答案是有,但比较tricky。方法就是在VEHandler开始处再次调用AddVectoredExceptionHandler,结束之前再RemoveVectoredExceptionHandler,在中间添加又一个VEH处理器。看上去比较疯狂,但确实能起作用。新添加的VEH可以处理原来的VEH中的问题。,这在某种程度上类似SEH,也巧妙的构成了一种平衡。

但是这要求原有的大量代码也要修改成这种方式,另外,使用起来不象使用__try,__except这么方便,第三点,VEH的结果选择,要么EXCEPTION_CONTINUE_EXECUTION,要么EXCEPTION_CONTINUE_SEARCH,没有第3种结果EXCEPTION_EXECUTE_HANDLER,这可是SEH中很有杀伤力的利器。第四点,VEH中缺乏终结器,即__finally,SEH中有,但在VEH存在的情况下,只有VEH交出控制权,SEH中的__finally才能起作用。从第三,第四两点来说,VEH比SEH缺乏处理异常的能力。

总之,从和原有的代码合作角度来看,还是从处理异常的能力能看,SEH仍然是当之无愧的首选。VEH的使用则要仔细测试,慎之又慎。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics