From: Carsten Schmidt Carsten on
Hi,

Sometimes I experience strange behavior when writing to the irp->MdlAddress
buffer of a disk filter driver I am writing.

In my IRP_MJ_READ routine I need to return the contents of an internal
buffer in stead of passing the request on to the disk driver.

If I enter the code below in the IRP_MJ_READ dispatch routine the assertion
occasionally fails, i.e., the RtlCopyMemory command did not copy correctly.


if (irp->MdlAddress) {
void* mdlBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
NormalPagePriority);
ULONG length = IoGetCurrentIrpStackLocation(irp)->Parameters.Read.Length;
RtlCopyMemory(mdlBuffer, buffer, length);
ASSERT(RtlEqualMemory(mdlBuffer, buffer, length )); // <- This assertion
occasionally fails
}


Typically irp->MdlAddress->MdlFlags is (MDL_IO_PAGE_READ | MDL_PAGES_LOCKED)
before the MmGetSystemAddressForMdlSafe() call and (MDL_IO_PAGE_READ |
MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA) afterwards.

What really puzzles me is that after one ore more attempts the test code
below succeeds. It looks like the MDL is not fully ready yet on the first
attempt and that a separate thread is building it simultaneously.


do {
differs = FALSE;
RtlFillMemory(mdlBuffer, length, 'X');
for (i = 0; i < length; ++i) {
if (buffer[i] != 'X') {
differs = TRUE;
KdPrint( ("Byte %d of %d differs.\n", i, length) );
}
}
} while (differs);


Can anybody please tell me what is going on.

Thanks

From: Alexander Grigoriev on
This is essentially the same memory that your application gives. If the
application is modifying the memory while you're copying there, you'll get a
mismatch.

"Carsten Schmidt" <Carsten Schmidt(a)discussions.microsoft.com> wrote in
message news:378D665B-1166-4C38-9362-B4927F395E51(a)microsoft.com...
> Hi,
>
> Sometimes I experience strange behavior when writing to the
> irp->MdlAddress
> buffer of a disk filter driver I am writing.
>
> In my IRP_MJ_READ routine I need to return the contents of an internal
> buffer in stead of passing the request on to the disk driver.
>
> If I enter the code below in the IRP_MJ_READ dispatch routine the
> assertion
> occasionally fails, i.e., the RtlCopyMemory command did not copy
> correctly.
>
>
> if (irp->MdlAddress) {
> void* mdlBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
> NormalPagePriority);
> ULONG length =
> IoGetCurrentIrpStackLocation(irp)->Parameters.Read.Length;
> RtlCopyMemory(mdlBuffer, buffer, length);
> ASSERT(RtlEqualMemory(mdlBuffer, buffer, length )); // <- This
> assertion
> occasionally fails
> }
>
>
> Typically irp->MdlAddress->MdlFlags is (MDL_IO_PAGE_READ |
> MDL_PAGES_LOCKED)
> before the MmGetSystemAddressForMdlSafe() call and (MDL_IO_PAGE_READ |
> MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA) afterwards.
>
> What really puzzles me is that after one ore more attempts the test code
> below succeeds. It looks like the MDL is not fully ready yet on the first
> attempt and that a separate thread is building it simultaneously.
>
>
> do {
> differs = FALSE;
> RtlFillMemory(mdlBuffer, length, 'X');
> for (i = 0; i < length; ++i) {
> if (buffer[i] != 'X') {
> differs = TRUE;
> KdPrint( ("Byte %d of %d differs.\n", i, length) );
> }
> }
> } while (differs);
>
>
> Can anybody please tell me what is going on.
>
> Thanks
>


From: Carsten Schmidt on
Thanks for your reply. It was much appreciated, but I'm afraid it didn't help
me much. Since I am in an IRP_MJ_READ request I am expected to write to the
buffer. Furthermore, the MDL_MAPPED_TO_SYSTEM_VA flag is not set, i.e., the
memory is not mapped to virtual memory yet, so no other thread can write to
the memory simultaneously.

However, after I posted this question I think I have come across a
explanation to what is happening. The memory manager has mapped some MDL
pages to a dummy page (http://www.microsoft.com/whdc/driver/tips/mdl.mspx).

"Carsten Schmidt" wrote:

> Hi,
>
> Sometimes I experience strange behavior when writing to the irp->MdlAddress
> buffer of a disk filter driver I am writing.
>
> In my IRP_MJ_READ routine I need to return the contents of an internal
> buffer in stead of passing the request on to the disk driver.
>
> If I enter the code below in the IRP_MJ_READ dispatch routine the assertion
> occasionally fails, i.e., the RtlCopyMemory command did not copy correctly.
>
>
> if (irp->MdlAddress) {
> void* mdlBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
> NormalPagePriority);
> ULONG length = IoGetCurrentIrpStackLocation(irp)->Parameters.Read.Length;
> RtlCopyMemory(mdlBuffer, buffer, length);
> ASSERT(RtlEqualMemory(mdlBuffer, buffer, length )); // <- This assertion
> occasionally fails
> }
>
>
> Typically irp->MdlAddress->MdlFlags is (MDL_IO_PAGE_READ | MDL_PAGES_LOCKED)
> before the MmGetSystemAddressForMdlSafe() call and (MDL_IO_PAGE_READ |
> MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA) afterwards.
>
> What really puzzles me is that after one ore more attempts the test code
> below succeeds. It looks like the MDL is not fully ready yet on the first
> attempt and that a separate thread is building it simultaneously.
>
>
> do {
> differs = FALSE;
> RtlFillMemory(mdlBuffer, length, 'X');
> for (i = 0; i < length; ++i) {
> if (buffer[i] != 'X') {
> differs = TRUE;
> KdPrint( ("Byte %d of %d differs.\n", i, length) );
> }
> }
> } while (differs);
>
>
> Can anybody please tell me what is going on.
>
> Thanks
>
From: Alexander Grigoriev on
No, the dummy page is not relevant to this.

Again, mapping to the system space doesn't make the memory protected from
other writers. It's just mapping (aliasing), not copying. If your
application is modifying the buffer at this time (by writing to the
user-mode address), you'll see the modifications at the system-mapped
address, and the other way around.

If your application accidentally passed the same buffer to two different
read requests from another threads at the same time, you may also see such
corruption.

"Carsten Schmidt" <CarstenSchmidt(a)discussions.microsoft.com> wrote in
message news:50E4B253-D482-4675-905A-9A884C8DD50B(a)microsoft.com...
> Thanks for your reply. It was much appreciated, but I'm afraid it didn't
> help
> me much. Since I am in an IRP_MJ_READ request I am expected to write to
> the
> buffer. Furthermore, the MDL_MAPPED_TO_SYSTEM_VA flag is not set, i.e.,
> the
> memory is not mapped to virtual memory yet, so no other thread can write
> to
> the memory simultaneously.
>
> However, after I posted this question I think I have come across a
> explanation to what is happening. The memory manager has mapped some MDL
> pages to a dummy page
> (http://www.microsoft.com/whdc/driver/tips/mdl.mspx).
>
> "Carsten Schmidt" wrote:
>
>> Hi,
>>
>> Sometimes I experience strange behavior when writing to the
>> irp->MdlAddress
>> buffer of a disk filter driver I am writing.
>>
>> In my IRP_MJ_READ routine I need to return the contents of an internal
>> buffer in stead of passing the request on to the disk driver.
>>
>> If I enter the code below in the IRP_MJ_READ dispatch routine the
>> assertion
>> occasionally fails, i.e., the RtlCopyMemory command did not copy
>> correctly.
>>
>>
>> if (irp->MdlAddress) {
>> void* mdlBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
>> NormalPagePriority);
>> ULONG length =
>> IoGetCurrentIrpStackLocation(irp)->Parameters.Read.Length;
>> RtlCopyMemory(mdlBuffer, buffer, length);
>> ASSERT(RtlEqualMemory(mdlBuffer, buffer, length )); // <- This
>> assertion
>> occasionally fails
>> }
>>
>>
>> Typically irp->MdlAddress->MdlFlags is (MDL_IO_PAGE_READ |
>> MDL_PAGES_LOCKED)
>> before the MmGetSystemAddressForMdlSafe() call and (MDL_IO_PAGE_READ |
>> MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA) afterwards.
>>
>> What really puzzles me is that after one ore more attempts the test code
>> below succeeds. It looks like the MDL is not fully ready yet on the first
>> attempt and that a separate thread is building it simultaneously.
>>
>>
>> do {
>> differs = FALSE;
>> RtlFillMemory(mdlBuffer, length, 'X');
>> for (i = 0; i < length; ++i) {
>> if (buffer[i] != 'X') {
>> differs = TRUE;
>> KdPrint( ("Byte %d of %d differs.\n", i, length) );
>> }
>> }
>> } while (differs);
>>
>>
>> Can anybody please tell me what is going on.
>>
>> Thanks
>>