Share via


セーフ ハンドルとクリティカル ファイナライズ

更新 : 2007 年 11 月

.NET Framework Version 2.0 より前は、オペレーティング システム ハンドルは IntPtr マネージ ラッパー オブジェクト内のみでカプセル化できました。ネイティブ コードと相互運用する場合はこの方法が便利でしたが、予期せず中止されたスレッド、スタック オーバーフローなどの非同期例外によってハンドルがリークされるおそれがありました。このような非同期例外は、オペレーティング システム リソースのクリーンアップの妨げとなり、プログラムのあらゆる場所で発生する可能性があります。発生しやすい場所としては、Microsoft SQL Server などのマネージ コードを実行するホストを使用するアプリケーションがあります。

状況によっては、プラットフォーム呼び出しでのメソッドの実行中に、ガベージ コレクションによってファイナライズ可能なオブジェクトが再生される可能性があります。そのプラットフォーム呼び出しに渡されたハンドルをファイナライザが解放すると、ハンドルの破損につながるおそれがあります。また、プラットフォーム呼び出し中 (ファイルの読み取り中など) にメソッドがブロックされている間に、ハンドルが再生される可能性もあります。

さらに重大な点は、Windows が積極的にハンドルをリサイクルするために、ハンドルがリサイクルされて、重要情報を含む別のリソースをポイントする可能性があることです。これはリサイクル攻撃と呼ばれ、データを破壊し、セキュリティ上の脅威となるおそれがあります。

.NET Framework 2.0 からは、SafeHandle クラスによってオブジェクトの有効期間に関するこのような問題の一部が簡略化されています。このクラスは、オペレーティング システム リソースがリークされないように、プラットフォーム呼び出しに統合されています。SafeHandle クラスは、処理を中断することなくハンドルの割り当てと解放を行うことで、オブジェクトの有効期間に関する問題を解決します。このクラスは、ハンドルが確実に閉じられるようにするクリティカル ファイナライザが含まれています。また、プラットフォーム呼び出しが破損状態にあると見られる場合でも、AppDomain のアンロード中に実行されることが保証されています。

SafeHandleCriticalFinalizerObject から継承されるため、すべての非クリティカル ファイナライザは、クリティカル ファイナライザの前に呼び出されます。ファイナライザは、同じガベージ コレクションの実行中に、有効でなくなったオブジェクトに対して呼び出されます。たとえば FileStream オブジェクトは、標準のファイナライザを実行して、ハンドルがリークされたりリサイクルされたりするリスクなしに既存のバッファ データを消去できます。クリティカル ファイナライザと非クリティカル ファイナライザ間のこの非常に弱い順序付けは、一般に使用されることを想定していません。その主な存在目的は、既存のライブラリでそのセマンティクスを変えずに SafeHandle を使用できるようにして、それらのライブラリの移行を支援することです。また、クリティカル ファイナライザとそれが呼び出す SafeHandle.ReleaseHandle() などのすべてのメソッドは、制約された実行領域内にあることが必要です。これにより、ファイナライザの呼び出し先で記述できるコードの内容が制限されます。

.NET Framework Version 2.0 からは、プラットフォーム呼び出し操作で、SafeHandle によってカプセル化されたハンドルの参照カウントのインクリメント、および完了時のカウントのデクリメントが自動的に行われるようになりました。これにより、ハンドルが予期せずリサイクルされたり閉じられたりしなくなります。

SafeHandle オブジェクトを構築する際に、基になるハンドルの所有権を指定できます。これにより、SafeHandle オブジェクトが破棄された後にそのオブジェクトがハンドルを解放するかどうかを制御します。これは、有効期間の要件が特殊であるハンドル、または第三者によって有効期間が制御されるハンドルを使用する場合に役立ちます。

セーフ ハンドル クラス

Microsoft.Win32.SafeHandles 名前空間には、ファイルおよびオペレーティング システムのハンドルをサポートする機能を提供するために、SafeHandle から継承されたクラスが含まれています。.NET Framework のセーフ ハンドル クラスを次の表にまとめます。

クラス

説明

SafeHandle

プラットフォーム呼び出し操作のハンドルをラップして、ファイナライズが中断せずに行われるようにします。このクラスは継承する必要があります。

SafeFileHandle

アンマネージ ファイル ハンドルへのアクセスを提供します。

SafeWaitHandle

アンマネージ待機ハンドルへのアクセスを提供します。

SafeHandleMinusOneIsInvalid

および

SafeHandleZeroOrMinusOneIsInvalid

カスタム セーフ ハンドル クラスの作成を可能にします。

参照

参照

SafeHandle

CriticalHandle

CriticalFinalizerObject