Partager via


Erreurs dans un environnement multiprocesseur

Sur le système d’exploitation basé sur NT, les pilotes sont multithreads ; ils peuvent recevoir plusieurs demandes d’E/S de différents threads en même temps. Lors de la conception d’un pilote, vous devez supposer qu’il sera exécuté sur un système SMP et prendre les mesures appropriées pour garantir l’intégrité des données.

Plus précisément, chaque fois qu’un pilote modifie des données d’objet global ou de fichier, il doit utiliser un verrou ou une séquence verrouillée pour empêcher les conditions de course.

Rencontrer une condition de race lors du référencement de données globales ou spécifiques à un objet de fichier

Dans l’extrait de code suivant, une condition de course peut se produire lorsque le pilote accède aux données globales sur 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);

Plusieurs threads entrant ce code à la suite d’un appel IOCTL peuvent provoquer une fuite de mémoire lorsque le pointeur est remplacé. Pour éviter ce problème, le pilote doit utiliser les routines ExInterlockedXxx ou un type de verrou lorsqu’il modifie les données globales. Les exigences du pilote déterminent les types de verrous acceptables. Pour plus d’informations, consultez Spin Locks, Kernel Dispatcher Objects et ExAcquireResourceSharedLite.

L’exemple suivant tente de réallouer une mémoire tampon spécifique au fichier (Endpoint-LocalAddress>) pour contenir l’adresse du point de terminaison :

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

Dans cet exemple, une condition de race peut se produire avec les accès à l’objet fichier. Étant donné que le pilote ne contient pas de verrous, deux demandes pour le même objet de fichier peuvent entrer cette fonction. Le résultat peut être des références à la mémoire libérée, plusieurs tentatives de libérer la même mémoire ou des fuites de mémoire. Pour éviter ces erreurs, les deux instructions if doivent être placées dans un verrou de rotation.