天天看點

驅動中為啥少有異常處理的代碼?

    今天整理ppt,突然想到一個現象:在WRK以及winddk sample源碼中很少見到異常處理相關的影子(指windows結構化異常處理SEH:__try/__exception,而不是C++标準提供的try/catch,kernel不支援C++異常)。按說,核心本身具有完整的異常處理機制,驅動作為核心的一部分,如果使用了異常處理塊,必然受到異常處理機制的保護。

    我首先想到的是在DISPATCH_LEVEL上發生了缺頁異常,由于換頁線程不被排程,是以該異常始終無法解決。在這樣的情景下,異常處理的确沒有任何意義。但是排除這種情況我實在想不出不使用異常處理的理由。查了一下MSDN "​​Handling Exceptions​​",他的解釋是:

1.讀寫來自使用者空間的記憶體時,需要在try/except塊中調用ProbeForWrite/ProbeForRead來檢查這部分記憶體是否可用。形如:

try {
    ...
    ProbeForWrite(Buffer, BufferSize, BufferAlignment);

    /* Note that any access (not just the probe, which must come first,
     * by the way) to Buffer must also be within a try-except.
     */
    ...
} except (EXCEPTION_EXECUTE_HANDLER) {
    /* Error handling code */
    ...
}      

這部分内容我并沒有覺得陌生,在Wrk源碼中不乏有像NtReadFile/NtWriteFile這樣從使用者态進入到核心态的stub函數,在其入口處會調用ProbeForxxx函數來檢查參數的可用性。

2.驅動中可以調用ExRaiseAccessViolation等函數抛出異常,驅動需要及時處理這些異常。我想,應該沒人會冒着藍屏的風險做這樣的操作吧,是以這個可以忽略。

3.部分Mm*系列的DDI,因為通路了使用者空間記憶體需要由try/exception保護。這部分DDI在其Remark部分标注有類似"Calls to MmProbeAndLockPages must be enclosed in a try/except block. If the pages do not support the specified operation, the routine raises the STATUS_ACCESS_VIOLATION or other exceptions."的字樣。換句話說,這類DDI是已知的雷區,進入前得有出意外的準備。

觀察上面3點,至少可以确定OS對驅動提供了有限的異常處理能力。但是,還是沒有讓我釋疑。倒在另一篇MSDN "​​Exception Handling When Accessing User-Mode Memory​​"中找到一句話:

"Note Aside from accessing and copying the user-mode value into a local variable, 
the driver should not perform any other operations inside the __try block.
 Other operations can cause their own exceptions to occur.
 The operating system handles these exceptions differently."      
"Exceptions processing takes a lot of space in stack 
and this can cause its overflow as stack size in kernel mode is very small (about 12 Kb). 
That's why one should work with exceptions very carefully."      

繼續閱讀