我在磁盘驱动器上开发了一个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;
}发布于 2017-02-17 23:42:15
下一行出错
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而不包含更多数据时才会产生错误。否则,您将覆盖已分配的内存(仅为相当大的内存(PVOID)),并创建错误。
以及IoBuildAsynchronousFsdRequest的完成情况。不幸的是,文档不是很好。在这里满足了
在调用IoFreeIrp之前,如果以下所有内容都是正确的,则需要另外一步来释放由IoBuildAsynchronousFsdRequest生成的IRP缓冲区: 缓冲区是从系统内存池中分配的。
但之后所有的注意力
Irp->MdlAddress字段是非空的。
然而,我们必须检查和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()
发布于 2016-09-22 09:58:11
我不太熟悉你在做什么的细节,下面是一些引起我注意的细节。
WriteDataIRPCompletion函数
PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT)上下文;// .删除[]写上下文->写缓冲区;如果(上下文)ExFreePool(上下文);
注意,您的writeContext来自于Context参数。但是,您似乎要删除/释放分配的内存两次。
ExFreePool函数文档状态:
指定要释放的池内存块的地址。
看起来,delete [] writeContext->writeBuffer;行可能导致了问题,只需要删除它。
就像现在一样,函数应该是freed的部分内存在调用ExFreePool、时已经是手动的deleted,但没有设置为,这反过来又导致ExFreePool在Context参数中接收到一个现在无效的指针(即指向非分配内存的非空指针),从而导致崩溃。
WriteToDeviceRoutine函数
ExFreePool的文档显式地声明它释放与其他函数(如ExAllocatePool和其他朋友)一起分配的内存。
但是,您的代码试图分别使用writeContext->writeBuffer /delete运算符直接分配/释放new。似乎您应该使用ExAllocatePool分配内存,然后使用ExFreePool进行释放,而不是像这样手动地执行操作。
这些函数可能是以一种特定的方式组织内存的,如果/当在ExFreePool中不满足这个预条件时,它可能会崩溃。
另外,似乎奇怪的是,在调用if(Context)之前检查ExFreePool是空的,但在尝试为本地writeContext变量键入强制转换并使用它之前就不是这样了。
也许你也应该在第一个使用点检查一下?如果Context总是非空的,那么在调用ExFreePool之前,检查可能也是不必要的。
https://stackoverflow.com/questions/39635484
复制相似问题