2

我在磁盘驱动程序上开发了一个 WDM 过滤器驱动程序。我想发送一个异步请求以在磁盘上写入数据。当我删除函数中的writeBuffer内存时,窗口会崩溃。WriteDataIRPCompletion

我的问题是:如何安全地释放writeBuffer内存而不会崩溃?

这是我的发送请求代码:

#pragma PAGEDCODE
NTSTATUS WriteToDeviceRoutine() {
    PMYDRIVER_WRITE_CONTEXT context = (PMYDRIVER_WRITE_CONTEXT)ExAllocatePool(NonPagedPool,sizeof(PMYDRIVER_WRITE_CONTEXT));
    context->writeBuffer = new(NonPagedPool) unsigned char[4096];

    PIRP pNewIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
         pdx->LowerDeviceObject,
         context->writeBuffer,(wroteRecordNodeCount<<SHIFT_BIT),
         &startingOffset,NULL);
   IoSetCompletionRoutine(pNewIrp,WriteDataIRPCompletion,context,TRUE,TRUE,TRUE);
   IoCallDriver(pdx->LowerDeviceObject,pNewIrp);
}

这是我的完成例程代码:

#pragma LOCKEDCODE
NTSTATUS WriteDataIRPCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP driverIrp,IN PVOID Context) {
   PMDL mdl,nextMdl;
   KdPrint((" WriteDataIRPCompletion \n"));
   PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context;
   if(driverIrp->MdlAddress!=NULL){
      for(mdl=driverIrp->MdlAddress;mdl!=NULL;mdl = nextMdl) {
         nextMdl = mdl->Next;
         MmUnlockPages(mdl);
         IoFreeMdl(mdl);
         KdPrint(("mdl clear\n"));
     }
     driverIrp->MdlAddress = NULL;
   }
   delete [] writeContext->writeBuffer;
   if(Context)
      ExFreePool(Context);

    KdPrint(("leave WriteDataIRPCompletion \n"));
    return STATUS_CONTINUE_COMPLETION;
}
4

2 回答 2

0

我不太熟悉你正在使用的细节,所以这里有一些引起我注意的细节。

WriteDataIRPCompletion功能

PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context;
// ...
delete [] writeContext->writeBuffer;
if(Context)
     ExFreePool(Context);

请注意,您writeContext源于您的Context论点。但是,您似乎要删除/释放分配的内存两次。

ExFreePool函数文档状态:

指定正在释放的池内存块的地址。

看起来这delete [] writeContext->writeBuffer;条线可能会导致问题,只需将其删除即可。

就像现在一样,应该由函数 d 的部分内存在您调用时free已经手动d ,但没有设置为,这反过来会导致接收一个现在无效的指针(即指向释放内存的指针)在其参数中,导致崩溃。deleteExFreePoolNULLExFreePoolContext

WriteToDeviceRoutine功能

for 的文档ExFreePool明确指出它会释放已分配给其他函数的内存,例如ExAllocatePool和其他朋友。

但是,您的代码正在尝试分别使用/运算符writeContext->writeBuffer直接分配/取消分配。似乎您应该分配内存然后释放内存,而不是尝试像那样手动执行操作。newdeleteExAllocatePoolExFreePool

这些函数可能会以特定的方式组织内存,如果/当这个前提条件在 中不满足时ExFreePool,它可能会以崩溃告终。


if(Context)在单独的注释中,您在调用之前检查 is null 似乎很奇怪ExFreePool,但在您尝试为局部writeContext变量进行类型转换并使用它之前检查不是上面的。

也许您还应该在第一个使用点进行检查?如果Context始终为非 null,则调用 之前也可能不需要检查ExFreePool

于 2016-09-22T09:58:11.010 回答
0

你在下一行出错

context = ExAllocatePool(NonPagedPool,sizeof(PMYDRIVER_WRITE_CONTEXT));

什么时候必须

context = ExAllocatePool(NonPagedPool,sizeof(MYDRIVER_WRITE_CONTEXT));

不是sizeof(PMYDRIVER_WRITE_CONTEXT),但sizeof(MYDRIVER_WRITE_CONTEXT)你分配的不是结构而是指向它的指针。

仅当您MYDRIVER_WRITE_CONTEXT包含单个字段writeBuffer且没有更多数据时,这不会产生错误。否则你会覆盖分配的内存(这只是 sizeof(PVOID)),这会产生错误

以及关于IoBuildAsynchronousFsdRequest. 不幸的是,文档不是很好。这里说

在调用 IoFreeIrp 之前,如果满足以下条件,则需要一个额外的步骤来为 IoBuildAsynchronousFsdRequest 构建的 IRP 释放缓冲区:

The buffer was allocated from system memory pool.

但随后所有的注意力

Irp->MdlAddress 字段不为 NULL。

但是我们必须检查和检查IRP_DEALLOCATE_BUFFER|IRP_BUFFERED_IO,否则我们可能会泄漏Irp->AssociatedIrp.SystemBuffer。需要下一个代码

if (Irp->Flags & IRP_BUFFERED_IO)
{
    if (Irp->Flags & IRP_INPUT_OPERATION)
    {
        if (!NT_ERROR(Irp->IoStatus.Status) && Irp->IoStatus.Information)
        {
            memcpy( Irp->UserBuffer, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information );
        }
    }

    if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
    {
        ExFreePool(Irp->AssociatedIrp.SystemBuffer);
        Irp->AssociatedIrp.SystemBuffer = 0;
    }

    Irp->Flags &= ~(IRP_DEALLOCATE_BUFFER|IRP_BUFFERED_IO);
}

并检查使用后if (writeContext) 已经writeContext->writeBuffer毫无意义和无意义。你真的需要检查context != NULL一下WriteToDeviceRoutine()

于 2017-02-17T23:42:15.570 回答