安全控制代碼和關鍵結束
更新:2007 年 11 月
在 .NET Framework 2.0 版之前,所有的作業系統控制代碼都只能被封裝在 IntPtr Managed 包裝函式物件。儘管這是與機器碼進行相互操作的方便作法,控制代碼卻可能因為未預期的執行緒中止或堆疊溢位 (Stack Overflow) 一類的非同步例外狀況 (Exception) 而遺漏。這些非同步例外狀況是清除作業系統資源的阻礙,而且可能會在程式中的任何位置發生。這些例外狀況最容易在使用執行 Managed 程式碼之主機的應用程式 (例如 Microsoft SQL Server) 中發生。
在某些狀況下,在平台叫用呼叫內執行方法時,都可以使用記憶體回收來回收可完成之物件。如果某個完成項釋放傳遞至該平台叫用呼叫的控制代碼,便可能會造成控制代碼損毀。當進行平台叫用呼叫 (例如讀取檔案) 期間而封鎖您的方法時,也可以回收控制代碼。
更為嚴重的是,由於 Windows 會積極回收控制代碼,控制代碼可以被回收並指向可能包含敏感資料的另一項資源。這種情形被稱為回收攻擊,而且可能會損毀資料並成為安全性威脅。
從 .NET Framework 2.0 開始,SafeHandle 類別 (Class) 便簡化了許多這些物件存留期 (Lifetime) 的問題,而且還與平台叫用整合,使作業系統資源不至於遺漏。SafeHandle 類別會在不受干擾的情況下指派和釋放控制代碼,以解決物件存留期的問題。其中包含一個關鍵的完成項,以確定控制代碼的關閉,並保證會在 AppDomain 卸載時執行,即使平台叫用呼叫在損毀狀態下時依然如此。
由於 SafeHandle 是從 CriticalFinalizerObject 繼承的,對於所有非關鍵完成項的呼叫都會在任何關鍵完成項之前進行。會在已不在相同記憶體回收行程中存在/運作的物件上,呼叫這些完成項。例如,FileStream 物件可以執行一般完成項以清除現有的緩衝資料,而不需擔心控制代碼遺漏或是被回收的風險。這種關鍵完成項與非關鍵完成項之間的弱式排列,並不適用於一般情況。這種排列的主要用意是要允許現有程式庫使用 SafeHandle 藉此進行程式庫的移轉,而不需要透過更改其語意 (Semantics) 的方法。此外,關鍵完成項和其所呼叫的任何項目,例如 SafeHandle.ReleaseHandle() 方法,都必須位於受到條件約束的執行區域中。這樣便會對可在完成項之呼叫圖形內寫入的程式碼施加條件約束。
從 .NET Framework 2.0 版開始,平台叫用作業都會自動遞增由 SafeHandle 所封裝的控制代碼參考次數 (Reference Count),並會在完成時遞減這些參考次數。如此即可確保控制代碼不會未預期地被回收或被關閉。
您可以在建構 SafeHandle 物件時指定基礎控制代碼的擁有權。這樣便能控制 SafeHandle 物件是否會在物件已經處置後釋放控制代碼。這種作法對於具有特殊存留期需求的控制代碼,或是使用其存留期由他人所控制的控制代碼都相當有用。
安全控制代碼類別
Microsoft.Win32.SafeHandles 命名空間 (Namespace) 包含衍生自 SafeHandle 的類別,以提供支援檔案和作業系統控制代碼的功能。下表摘要 .NET Framework 安全控制代碼的類別。
類別 |
描述 |
---|---|
包裝平台叫用作業的控制代碼,這些作業確保最終化不會受到干擾。此類別必須是繼承的類別。 |
|
提供對 Unmanaged 檔案控制代碼 (File Handle) 的存取。 |
|
提供對 Unmanaged 等候控制代碼的存取。 |
|
和 |
讓您能夠建立自訂的安全控制代碼類別。 |