Compartir vía


Errores en un entorno de varios procesadores

En el sistema operativo basado en NT, los controladores son multiproceso; pueden recibir varias solicitudes de E/S de diferentes subprocesos al mismo tiempo. Al diseñar un controlador, debe suponer que se ejecutará en un sistema SMP y tomar las medidas adecuadas para garantizar la integridad de los datos.

En concreto, cada vez que un controlador cambia los datos globales o de objeto de archivo, debe usar un bloqueo o una secuencia interbloqueada para evitar condiciones de carrera.

Encontrar una condición de carrera al hacer referencia a datos globales o específicos del objeto de archivo

En el siguiente fragmento de código, se puede producir una condición de carrera cuando el controlador accede a los datos globales en 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);

Varios subprocesos que escriben este código como resultado de una llamada IOCTL podrían provocar una pérdida de memoria a medida que se sobrescribe el puntero. Para evitar este problema, el controlador debe usar las rutinas ExInterlockedXxx o algún tipo de bloqueo cuando cambia los datos globales. Los requisitos del controlador determinan los tipos aceptables de bloqueos. Para obtener más información, vea Bloqueos de número, objetos de distribuidor de kernel y ExAcquireResourceSharedLite.

En el ejemplo siguiente se intenta reasignar un búfer específico del archivo (Endpoint-LocalAddress>) para contener la dirección del punto de conexión:

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

En este ejemplo, se podría producir una condición de carrera con accesos al objeto de archivo. Dado que el controlador no contiene ningún bloqueo, dos solicitudes para el mismo objeto de archivo pueden especificar esta función. El resultado puede ser referencias a memoria libre, varios intentos de liberar la misma memoria o pérdidas de memoria. Para evitar estos errores, las dos instrucciones if deben incluirse en un bloqueo de número.