Я разработал драйвер фильтра WDM для драйвера диска. Я хочу отправить асинхронный запрос на запись данных на диск. Windows вылетит при удалении 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;
}
вы ошиблись в следующей строке
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 требуется дополнительный шаг, чтобы освободить
буфер для IRP, созданный IoBuildAsynchronousFsdRequest, если
Следующее все верно: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()
Я не слишком знаком со спецификой того, с чем вы работаете, поэтому вот несколько деталей, которые привлекли мое внимание.
WriteDataIRPCompletion
функцияPMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context; // ... delete [] writeContext->writeBuffer; if(Context) ExFreePool(Context);
Обратите внимание, что ваш writeContext
происходит от вашего Context
аргумент. Тем не менее, вы, кажется, удаляете / освобождаете выделенную память дважды.
ExFreePool
функция документы государство:
Указывает адрес освобождаемого блока памяти пула.
Похоже, delete [] writeContext->writeBuffer;
линия может быть причиной проблемы, и это просто нужно удалить.
Как сейчас, часть памяти, которая должна быть free
д функция уже была вручную delete
d к тому времени, когда вы вызываете ExFreePool
, но не установлено NULL
, что в свою очередь вызывает ExFreePool
получить недействительный теперь указатель (то есть ненулевой указатель, указывающий на нераспределенную память) в своем Context
аргумент, вызывающий аварию.
WriteToDeviceRoutine
функцияДокументация для ExFreePool
явно заявляет, что освобождает память, выделенную другим функциям, таким как ExAllocatePool
и другие друзья.
Тем не менее, ваш код пытается выделить / освободить writeContext->writeBuffer
непосредственно используя new
/delete
операторы соответственно. Кажется, вы должны распределять свою память ExAllocatePool
а затем избавиться от ExFreePool
вместо того, чтобы пытаться делать такие вещи вручную, как это.
Эти функции могут организовывать память определенным образом, и если / когда это предварительное условие не выполняется в ExFreePool
, это может привести к аварии.
На отдельном примечании кажется странным, что вы проверяете if(Context)
является нулевым перед вызовом ExFreePool
, но не выше, прежде чем пытаться набрать для вашего местного writeContext
Переменная и использовать его.
Может быть, вы также должны проверить в этой первой точке использования? Если Context
является всегда не нулевой, тогда проверка может быть ненужной до вызова ExFreePool
,