マルチプロセッサ環境におけるエラー
NT ベースのオペレーティング システムでは、ドライバーはマルチスレッドです。異なるスレッドから複数の I/O 要求を同時に受信できます。 ドライバーを設計するときは、SMP システム上で実行されることを想定し、データの整合性を確保するための適切な対策を講じなければなりません。
具体的には、ドライバーがグローバルまたはファイル オブジェクト のデータを変更するたびに、競合状態を防ぐためにロックまたはインターロックされたシーケンスを使用する必要があります。
グローバルまたはファイル オブジェクト固有のデータを参照するときの競合状態の発生
次のコード スニペットでは、ドライバーが Data.LpcInfo のグローバル データにアクセスするときに競合状態が発生する可能性があります。
PLPC_INFO pLpcInfo = &Data.LpcInfo; //Pointer to global data
...
...
// This saved pointer may be overwritten by another thread.
pLpcInfo->LpcPortName.Buffer = ExAllocatePool(
PagedPool,
arg->PortName.Length);
IOCTL 呼び出しの結果としてこのコードを入力する複数のスレッドは、ポインターが上書きされるときにメモリ リークを引き起こす可能性があります。 この問題を回避するには、グローバル データを変更するときに、ドライバーが ExInterlockedXxx ルーチンまたは何らかの種類のロックを使用する必要があります。 ドライバーの要件によって、許容されるロックの種類が決まります。 詳細については、「スピン ロック」、「カーネル ディスパッチャー オブジェクト」、「ExAcquireResourceSharedLite」を参照してください。
次の例では、エンドポイント アドレスを保持するために、ファイル固有のバッファー (Endpoint->LocalAddress) の再割り当てを試みます。
Endpoint = FileObject->FsContext;
if ( Endpoint->LocalAddress != NULL &&
Endpoint->LocalAddressLength <
ListenEndpoint->LocalAddressLength ) {
FREE_POOL (Endpoint->LocalAddress,
LOCAL_ADDRESS_POOL_TAG
);
Endpoint->LocalAddress = NULL;
}
if ( Endpoint->LocalAddress == NULL ) {
Endpoint->LocalAddress =
ALLOCATE_POOL (NonPagedPool,
ListenEndpoint->LocalAddressLength,
LOCAL_ADDRESS_POOL_TAG);
}
この例では、ファイル オブジェクトへのアクセスで競合状態が発生する可能性があります。 ドライバーはロックを保持しないため、同じファイル オブジェクトに対して 2 つの要求がこの関数を入力できます。 その結果、解放されたメモリへの参照、同じメモリを複数回解放しようとしたり、メモリ リークが発生したりする可能性があります。 これらのエラーを回避するには、2 つの if ステートメントをスピン ロックで囲む必要があります。