多處理器環境中的錯誤
在 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);
}
在此範例中,可能會有存取檔案物件的競爭狀況。 因為驅動程式不會保留任何鎖定,所以相同檔案物件的兩個要求可以進入此函式。 結果可能是釋放記憶體的參考、多次嘗試釋放相同的記憶體,或記憶體流失。 若要避免這些錯誤,兩個 if 語句應該以微調鎖定括住。