多处理器环境中的错误

在基于 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 例程或某种类型的锁。 驱动程序的要求决定了可接受的锁类型。 有关详细信息,请参阅 Spin LocksKernel Dispatcher 对象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 语句括在旋转锁中。