Fehler in einer Multiprozessorumgebung

Auf dem NT-basierten Betriebssystem werden Treiber multithreaded; Sie können mehrere E/A-Anforderungen von verschiedenen Threads gleichzeitig empfangen. Beim Entwerfen eines Treibers müssen Sie davon ausgehen, dass er auf einem SMP-System ausgeführt wird, und die entsprechenden Maßnahmen ergreifen, um die Datenintegrität sicherzustellen.

Insbesondere, wenn ein Treiber globale oder Dateiobjektdaten ändert, muss er eine Sperre oder eine ineinandergreifende Sequenz verwenden, um Rennbedingungen zu verhindern.

Beim Verweisen auf globale oder dateiobjektspezifische Daten tritt eine Racebedingung auf.

Im folgenden Codeausschnitt kann eine Racebedingung auftreten, wenn der Fahrer auf die globalen Daten unter Data.LpcInfo zugreift:

   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);

Mehrere Threads, die diesen Code als Ergebnis eines IOCTL-Aufrufs eingeben, können zu einem Speicherverlust führen, wenn der Zeiger überschrieben wird. Um dieses Problem zu vermeiden, sollte der Treiber die ExInterlockedXxx-Routinen oder eine Art von Sperre verwenden, wenn er die globalen Daten ändert. Die Anforderungen des Treibers bestimmen die zulässigen Arten von Sperren. Weitere Informationen finden Sie unter Spin Locks, Kernel Dispatcher Objects und ExAcquireResourceSharedLite.

Im folgenden Beispiel wird versucht, einen dateispezifischen Puffer (Endpoint-LocalAddress>) neu zuzuordnen, um die Endpunktadresse zu speichern:

   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);
   }

In diesem Beispiel kann eine Racebedingung mit Zugriffen auf das Dateiobjekt auftreten. Da der Treiber keine Sperren enthält, können zwei Anforderungen für dasselbe Dateiobjekt in diese Funktion gelangen. Das Ergebnis können Verweise auf freigegebenen Arbeitsspeicher, mehrfache Versuche, denselben Arbeitsspeicher freizugeben, oder Speicherverluste sein. Um diese Fehler zu vermeiden, sollten die beiden if-Anweisungen in eine Drehsperre eingeschlossen werden.