IoBuildAsynchronousFsdRequest with IRP_MJ_WRITE
IoBuildAsynchronousFsdRequest with IRP_MJ_WRITE
我在磁盘驱动程序上开发了一个WDM筛选器驱动程序。我想发送一个异步请求以在磁盘上写入数据。当我删除WriteDataIRPCompletion
函数中的writeBuffer
内存时,窗口将崩溃。
我的问题是:如何安全地释放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 clearn"));
}
driverIrp->MdlAddress = NULL;
}
delete [] writeContext->writeBuffer;
if(Context)
ExFreePool(Context);
KdPrint(("leave WriteDataIRPCompletion n"));
return STATUS_CONTINUE_COMPLETION;
}
下一行出错
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 之前,需要执行额外的步骤来释放 由 IoBuildAsyncFsdRequest 构建的 IRP 的缓冲区,如果 以下都是正确的:
The buffer was allocated from system memory pool.
但随后所有的注意力都为
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()
我不太熟悉你正在使用的细节,所以这里有一些细节引起了我的注意。
在WriteDataIRPCompletion
函数
中PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context; // ... delete [] writeContext->writeBuffer; if(Context) ExFreePool(Context);
请注意,您的writeContext
源自您的Context
参数。但是,您似乎删除/释放了两次分配的内存。
ExFreePool
函数文档指出:
指定正在解除分配的池内存块的地址。
看起来delete [] writeContext->writeBuffer;
行可能导致问题,只需要将其删除即可。
就像现在一样,应该由函数free
的部分内存已经在您调用 ExFreePool
时手动delete
d,但未设置为 NULL
,这反过来又导致ExFreePool
在其 Context
参数中接收现在无效的指针(即指向已解除分配的内存的非空指针(, 导致崩溃。
在WriteToDeviceRoutine
函数
中ExFreePool
的文档明确指出,它会释放已分配给其他函数(如ExAllocatePool
和其他好友(的内存。
但是,您的代码尝试分别使用 new
/delete
运算符直接分配/释放writeContext->writeBuffer
。似乎您应该使用ExAllocatePool
分配内存,然后使用ExFreePool
进行分配,而不是尝试像那样手动执行操作。
这些功能可能以特定的方式组织内存,如果/当ExFreePool
中不满足此前提条件时,它可能会崩溃。
另外,在调用 ExFreePool
之前检查 if(Context)
为 null 似乎很奇怪,但在您尝试为局部 writeContext
变量进行类型转换并使用它之前,则不检查上面。
也许您还应该在第一个使用点进行检查?如果Context
始终为非 null,则在调用 ExFreePool
之前也可能不需要检查。
- 尝试链接我的着色器时,我收到错误代码"error c5145 must write to gl_position"
- 当客户端在 write() 期间终止连接时,由对等套接字错误重置连接
- Qt 写入 xml: QIODevice::write (QFile, "D:/logs.xml" ): 设备未打开
- write() 和 read() 中几乎没有混淆
- OpenCV-contrib/Python/Windows:Tracker.write() 在 matrix_wrap.
- asio::read() 需要很长时间,使用 asio::write 没有问题
- 封送指向结构异常"cannot Read or Write protected memory"的指针数组的指针数组
- BLE gattServer.write()重载函数
- C++ write(); 反向写入给定的字节值
- 使用 QFile::write 的正确方法?
- C++ UDP 广播使用 ::write
- 是否可以从从 QPrintPreviewDialog 调用的 QPrinter 对话框中删除"Write to PDF"?
- 为什么 fstream.read 和 fstream.write 使用 char 而不是无符号字符?
- 使用 insertion(<<) 运算符和 "write" 函数在 C++ 中显示数据有什么区别?
- 一次读取一个字符的文件,直到使用 read(2) 和 write(2) 换行符
- char* 如何读取十六进制的这个整数?它在 ostream::write() 中是如何工作的
- 在 boost::asio::write 之后使用 TCP
- 如何使用write()函数将结构写入文件
- 没有匹配函数来调用"std::basic_ofstream<char>::write(std::string*, long long unsigned int)"
- QNetwork回复 "unable to write"