[读书笔记] 关于Windows的结构化异常处理SEH(一)

结构化异常处理(一下简称SEH),实际上包含两方面的功能:终止处理(termination handling)和异常处理(exception handling),这篇笔记主要是关于终止处理,异常处理以后再看。

终止处理程序确保不管一个代码块是如何退出的,另一个代码块(终止处理程序)都能被执行。

*其实用代码表示就是

	__try
	{
		// 受保护代码
	}
	__finally
	{
		// 终止处理程序
	}
即使在受保护代码中使用return,goto之类的跳转语句,finally块中的终止处理代码都能被执行,绝大多数情况下这是正确的,还有少数情况下终止处理程序不能被执行,例如调用了ExitProcess, ExitThread, TerminateProcess, TerminateThread, 或者进程直接被终止,异常导致SEH链中断,或者异常发生在异常过滤程序里,这些情况下finally块中的终止处理代码不会被执行。


*关于开销

一般有三种不同的情况下,会进入终止处理程序中执行代码:

1.try块执行完毕后正常进入finally块

2.try块中的return之类的跳转语句执行导致进入finally块(会导致局部展开,见下文)

3.try块代码发生异常,而此类异常又不至于导致进程直接终止(会导致全局展开,见下文)

第一种情况下,控制流是按照正常的代码顺序进入finally块中,实际上基本上没有额外的开销(只需要额外执行一条机器指令),这是最好的情况,写代码时尽量让控制流走这条路;第二种情况下,在编译器发现try块中有return之类的跳转语句时会生成一些额外代码来保证SEH的机制,这样就会影响程序的性能,例如,try中有一个return语句,那么当编译器检查代码时就会生成一些代码将返回值保存在一个临时变量里,然后再执行finally块,执行结束后再将临时变量的值返回给函数的调用者(这就是“局部展开(local unwind)”)。第三种情况,全局展开,这个要复杂一些要分情况套路,以后的文章会讨论。

所以,应该尽量避免在try中使用return语句,如果非要在try中做一些跳出操作的话,可以使用微软C++编译器提供的关键字__leave,这个关键字会导致代码控制流跳转到try的闭花括号处,也就是会让控制流正常进入finally,这样就将第二种情况转换成了第一种情况,开销很小。

最后,在finally块中调用Bool AbnormalTermination();函数可以检查控制流是怎么进入finally块的,返回false表示控制流正常进入finally,返回true表示遇到了局部展开或全局展开,此函数由编译器实现。


总结:正确的使用终止处理程序对程序性能和体积的影响是很微小的,而且很多情况下还可以优化程序结构。


end.

第一遍读这几章,理解有误处欢迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章