Win32 SEH 本質是:異常發生時,OS 呼叫用戶定義的回呼函數。回呼原型:
EXCEPTION_DISPOSITION __cdecl _except_handler(
EXCEPTION_RECORD *ExceptionRecord,
void *EstablisherFrame,
CONTEXT *ContextRecord,
void *DispatcherContext);
EXCEPTION_RECORD:異常代碼 (如 0xC0000005)、位址、參數。CONTEXT:異常瞬間的寄存器快照 (EIP、ESP、EAX...),可修改以修復錯誤。EXCEPTION_REGISTRATION:鏈表節點,含 prev (前一節點) 與 handler (回呼指標)。線程資訊塊 (TIB/TEB) 的 FS:[0] 指向鏈表頭。OS 遍歷鏈表,尋找願意處理異常的回呼 (返回 ExceptionContinueExecution);拒絕處理則返回 ExceptionContinueSearch 繼續向下。
內嵌組語建立 EXCEPTION_REGISTRATION 於堆疊,修改 FS:[0],故意觸發存取違例 (寫入位址 0),回呼中修正 EAX 指向合法記憶體並返回 ExceptionContinueExecution,指令重試成功。展示 SEH 最原始運作面貌。
若內層回呼拒絕處理,外層處理後,系統會二次遍歷鏈表,旗標帶 EH_UNWINDING (2) 再次呼叫內層回呼,給予清理機會 (呼叫解構函數、執行 __finally)。此機制確保非正常退出時資源正確釋放。
進程啟動時 BaseProcessStart 以 __try/__except 包裹入口點,安裝預設處理器於鏈表尾。未處理異常時呼叫 UnhandledExceptionFilter:顯示錯誤對話框、支援 JIT 除錯、或直接終止進程。服務進程則呼叫 ExitThread 僅終止故障線程。
Visual C++ 封裝 OS SEH,提供 __try/__except 模型:
EXCEPTION_REGISTRATION 對應整個函數,handler 固定指向 __except_handler3。scopetable (過濾器/處理器地址陣列)、trylevel (當前嵌套層級)、_ebp (上一層 EBP)。__except_handler3 依 trylevel 索引 scopetable,呼叫過濾器運算式;若返回 EXCEPTION_EXECUTE_HANDLER,呼叫 __global_unwind2 展開幀,再呼叫 __local_unwind2 執行區域清理,最後跳轉至 __except 區塊 (不返回)。GetExceptionInformation/GetExceptionCode 為編譯器內建函數,直接讀取幀中預留的 EXCEPTION_POINTERS。示範程式遍歷 FS:[0] 鏈表,列印每個幀位址、處理器、scopetable 內容。輸出證實:多個函數共用 __except_handler3,最底層幀來自 CRT BaseProcessStart (位於 KERNEL32.dll)。