[讀書筆記] 關於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.

第一遍讀這幾章,理解有誤處歡迎指正。

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