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。ただし、割り当てられたメモリを2回削除/解放しているようです。

ExFreePool関数ドキュメントの状態:

割り当てを解除するプール メモリのブロックのアドレスを指定します。

行が問題を引き起こしているdelete [] writeContext->writeBuffer;可能性があり、削除する必要があるようです。

現時点では、関数によって d されるべきメモリの一部は、を呼び出した時点freeですでに手動でd されていますが、 に設定されていないため、無効なポインタ (つまり、null 以外の割り当て解除されたメモリを指すポインター) を引数に指定すると、クラッシュが発生します。deleteExFreePoolNULLExFreePoolContext

WriteToDeviceRoutine機能中

のドキュメントには、や他の友人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 に答える