IoCompleteRequest issue

I am generating an IRP to send to the next lower driver using IoBuildDeviceIoControlRequest with the following code:

KSPROPERTY* pProp;
pProp = (KSPROPERTY*)ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPROPERTY), ‘prIl’);
pProp->Set = KSPROPSETID_Topology;
pProp->Id = KSPROPERTY_TOPOLOGY_NODES;
pProp->Flags = KSPROPERTY_TYPE_GET;

// Allocate output buffer
ULONG uOutBufSize = 2000;
BYTE* pOutBuf = (BYTE*)ExAllocatePoolWithTag(NonPagedPool, uOutBufSize, ‘prIl’);

// Event we must supply and wait on if the lower driver returns a pending status
KEVENT ev;
KeInitializeEvent(&ev, NotificationEvent, FALSE);
IO_STATUS_BLOCK iosb;

// Build the Irp
PIRP pRequest = IoBuildDeviceIoControlRequest(
IOCTL_KS_PROPERTY
, pLowerDevice
, (PVOID)pProp
, sizeof(KSPROPERTY)
, (PVOID)pOutBuf
, uOutBufSize
, FALSE
, &ev
, &iosb);

// Set the target FileObject to the filter we are querying
PIO_STACK_LOCATION pStack = IoGetNextIrpStackLocation(pRequest);
pStack->FileObject = pFileObject;

// Pass the request to the next lowest device
NTSTATUS status = IoCallDriver(pLowerDevice, pRequest);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&ev, Executive, KernelMode, FALSE, NULL);
}
— some trivial logic concerning the output buffer —
IoCompleteRequest(pRequest, IO_NO_INCREMENT);

When I complete the request as per the documentation for IoBuildDeviceIoControlRequest I get a bugcheck:
PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc)

Stepping through with windbg I see that the IRP I have created becomes invalid memory immediately after the call to IoCallDriver. This is why I am assuming that the call to IoCompleteRequest is crashing. But is this expected? I thought it was my responsibility to complete the IRP?

Cheers,
BJW

Completion is to pass the request up the stack, since you created the
request you should not complete it. Just use IoFreeIrp to release the
memory.

Don Burn
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@nchsoftware.com
Sent: Monday, March 17, 2014 7:39 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] IoCompleteRequest issue

I am generating an IRP to send to the next lower driver using
IoBuildDeviceIoControlRequest with the following code:

KSPROPERTY* pProp;
pProp = (KSPROPERTY*)ExAllocatePoolWithTag(NonPagedPool,
sizeof(KSPROPERTY), ‘prIl’);
pProp->Set = KSPROPSETID_Topology;
pProp->Id = KSPROPERTY_TOPOLOGY_NODES;
pProp->Flags = KSPROPERTY_TYPE_GET;

// Allocate output buffer
ULONG uOutBufSize = 2000;
BYTE* pOutBuf = (BYTE*)ExAllocatePoolWithTag(NonPagedPool, uOutBufSize,
‘prIl’);

// Event we must supply and wait on if the lower driver returns a pending
status
KEVENT ev;
KeInitializeEvent(&ev, NotificationEvent, FALSE);
IO_STATUS_BLOCK iosb;

// Build the Irp
PIRP pRequest = IoBuildDeviceIoControlRequest(
IOCTL_KS_PROPERTY
, pLowerDevice
, (PVOID)pProp
, sizeof(KSPROPERTY)
, (PVOID)pOutBuf
, uOutBufSize
, FALSE
, &ev
, &iosb);

// Set the target FileObject to the filter we are querying
PIO_STACK_LOCATION pStack = IoGetNextIrpStackLocation(pRequest);
pStack->FileObject = pFileObject;

// Pass the request to the next lowest device
NTSTATUS status = IoCallDriver(pLowerDevice, pRequest);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&ev, Executive, KernelMode, FALSE, NULL);
}
— some trivial logic concerning the output buffer —
IoCompleteRequest(pRequest, IO_NO_INCREMENT);

When I complete the request as per the documentation for
IoBuildDeviceIoControlRequest I get a bugcheck:
PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc)

Stepping through with windbg I see that the IRP I have created becomes
invalid memory immediately after the call to IoCallDriver. This is why I am
assuming that the call to IoCompleteRequest is crashing. But is this
expected? I thought it was my responsibility to complete the IRP?

Cheers,
BJW


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Thanks, Don. What you say makes sense and works, but it seems to contradict the documentation:

“IRPs that are created by IoBuildDeviceIoControlRequest must be completed by a driver’s call to IoCompleteRequest. A driver that calls IoBuildDeviceIoControlRequest must not call IoFreeIrp, because the I/O manager frees these synchronous IRPs after IoCompleteRequest has been called.”

Am I reading it wrong?

An IoBuild created irp needs to completed back to the Io manager, not IoFree’d

d

Bent from my phone


From: Don Burnmailto:xxxxx
Sent: ?3/?17/?2014 4:45 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: RE: [ntdev] IoCompleteRequest issue

Completion is to pass the request up the stack, since you created the
request you should not complete it. Just use IoFreeIrp to release the
memory.

Don Burn
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@nchsoftware.com
Sent: Monday, March 17, 2014 7:39 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] IoCompleteRequest issue

I am generating an IRP to send to the next lower driver using
IoBuildDeviceIoControlRequest with the following code:

KSPROPERTY* pProp;
pProp = (KSPROPERTY*)ExAllocatePoolWithTag(NonPagedPool,
sizeof(KSPROPERTY), ‘prIl’);
pProp->Set = KSPROPSETID_Topology;
pProp->Id = KSPROPERTY_TOPOLOGY_NODES;
pProp->Flags = KSPROPERTY_TYPE_GET;

// Allocate output buffer
ULONG uOutBufSize = 2000;
BYTE* pOutBuf = (BYTE*)ExAllocatePoolWithTag(NonPagedPool, uOutBufSize,
‘prIl’);

// Event we must supply and wait on if the lower driver returns a pending
status
KEVENT ev;
KeInitializeEvent(&ev, NotificationEvent, FALSE);
IO_STATUS_BLOCK iosb;

// Build the Irp
PIRP pRequest = IoBuildDeviceIoControlRequest(
IOCTL_KS_PROPERTY
, pLowerDevice
, (PVOID)pProp
, sizeof(KSPROPERTY)
, (PVOID)pOutBuf
, uOutBufSize
, FALSE
, &ev
, &iosb);

// Set the target FileObject to the filter we are querying
PIO_STACK_LOCATION pStack = IoGetNextIrpStackLocation(pRequest);
pStack->FileObject = pFileObject;

// Pass the request to the next lowest device
NTSTATUS status = IoCallDriver(pLowerDevice, pRequest);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&ev, Executive, KernelMode, FALSE, NULL);
}
— some trivial logic concerning the output buffer —
IoCompleteRequest(pRequest, IO_NO_INCREMENT);

When I complete the request as per the documentation for
IoBuildDeviceIoControlRequest I get a bugcheck:
PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc)

Stepping through with windbg I see that the IRP I have created becomes
invalid memory immediately after the call to IoCallDriver. This is why I am
assuming that the call to IoCompleteRequest is crashing. But is this
expected? I thought it was my responsibility to complete the IRP?

Cheers,
BJW


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

@Doron:
This link: http://support.microsoft.com/kb/326315 shows IRP handling examples and in each case the IRP is not completed. If I follow this tactic in my driver then everything works well, but is in apparent contradiction with the formal documentation. Can you shed any light on this for me?
Cheers,
BJW

The documentation means IoCompleteRequest (in the target driver) will free the IRP eventually. You should not call it an extra time.

Ok thanks, Alex. I did not read it that way at all. I must have read through it 100 times and not once thought to interpret it that way :slight_smile:

Thanks all!
BJW

Sorry to do this, but…

I *hate* these IoBuildXxx functions. The only purpose they serve in most cases is to screw people up and cause them to do things they don’t intend.

So I have to ask: do you REALLY want to call this function? Are you running in the context of a known process and thread, so you explicitly want to create a threaded IRP?? Because that’s the only time calling this function is valid.

Peter
OSR
@OSRDrivers

I think so. My driver is an upper filter, and I am intercepting an IRP during audio pin creation. Most of the time I can read what I need from the creation request, but for some hardware I need further information about the pin. So I create and send the IRP to the driver for info on its topology which gets me what I need.

Does that sound ok?

> I *hate* these IoBuildXxx functions.

+1


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

No, it does not.

Nothing you’ve said indicates to me you want to send the IRP in the context of a particular thread. Now, I know exactly zero about the audio stack, so…

Why use this function ? Why not just allocate an IRP and set it up, and IoCallDriver it… And skip using the IoBuildXxxx function which is basically just laying in wait to screw people up.

Peter
OSR
@OSRDrivers

If IOCTL_KS_PROPERTY never block indefinitely, there is no reason whatsoever to use threaded IRP. It wounds like this IOCTL is a simple software query that doesn’t need to access any hardware. But if there is any device that NEEDS to access hardware, and such access might sometimes hang for long time, then you must use a threaded IRP. Or set a cancel routine on your original IRP and cancel your secondary IRP.

There is nothing wrong with IoBuildXxxx, if you use it exactly as prescribed (and know how IRPs work in general).

xxxxx@nchsoftware.com wrote:

I think so. My driver is an upper filter, and I am intercepting an IRP during audio pin creation. Most of the time I can read what I need from the creation request, but for some hardware I need further information about the pin. So I create and send the IRP to the driver for info on its topology which gets me what I need.

Does that sound ok?

No. There is a huge issue here that you do not understand.

IOCTL_KS_PROPERTY, like all of the KS ioctls, is METHOD_NEITHER. You
are assuming that it neatly follows the rules for a direct I/O ioctl,
but it does not. The KS ioctls are not well-behaved. For one thing,
the SystemBuffer in the IRP must a concatenation of the output buffer
and the input buffer. AVStream drivers do not look in the input buffer
for the KSPROPERTY structure, they look at the end of
Irp->AssociatedIrp.SystemBuffer. That means you always have to override
Irp->AssociatedIrp.SystemBuffer after you create the IRP.

Another issue here is that the property you’re asking for is variable
sized. You need to send one request without a buffer, which will return
the correct size to you in iosb.Information, then send another request
with that size. Assuming that 2000 bytes is enough is crappy programming.

So, send one request where the input buffer is the KSPROPERTY and the
output buffer is null. Set SystemBuffer to the KSPROPERTY. Send that
off. Then, allocate a buffer that is iosb.Information +
sizeof(KSPROPERTY). Copy the KSPROPERTY structure to
&buffer[iosb.Information]. Now, create the IRP, using iosb.Information
as the output buffer size, and set SystemBuffer to the allocated buffer.

That should work.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

@Tim:
Ok, thanks for that. I was wondering how to get the correct size and couldn’t figure it out so I just put in an overkill. I know it’s bad form, but as I said I couldn’t find the correct method.

I will also amend my approach to do as you say with the with the concatenated buffers. I have had similar issues in the past with the KS ioctls which I think you corrected me on, so I should have known better - it just slipped my mind.

@Peter, Alex:
The reason I think I need to create a threaded IRP is:
I need to determine if the IRP I am intercepting relates to a specific audio node. If it does I need to take a number of specific actions before the IRP is completed.

Cheers,
BJW

>The reason I think I need to create a threaded IRP is: I need to determine if the IRP I am intercepting relates to a specific audio node.

I don’t see how a threaded IRP helps for that. Its only big advantage is that it will get canceled if the thread is getting killed.

Here is my logic:
A threaded IRP is synchronous. My current design depends on this because when I intercept audio pin creation IRPs I need to determine if the pin being created is the one I am targeting. If I don’t do this synchronously and use a completion routine instead I find that it can get called too late and I miss my chance to read the audio stream.
Cheers,
BJW

>A threaded IRP is synchronous.

A threaded IRP is only synchronous if you wait for its completion immediately after sending it down. With the same effect, you can use a hand-built IRP (IoAllocateIrp).

If the driver you’re calling completes the particular request immediately (in your IoCallDriver context), the IRP will always behave as synchronous. In other words, a/synchronous behavior depends on the target driver, not on how you built the request.

Not to be a pedant, but there is no such thing as a synchronous IRP. There is only asynchronous or synchronous processing of an IRP by a driver. This has nothing to do with threading.

In other words, to be explicit, there is nothing inherently more or less synchronous about a threaded IRP than a non-threaded IRP.

“Threaded” in the context of IRPs simply means the IRP is linked into the currently executing thread’s IRP list. As we’ve been telling you, this makes whatever thread happens to be running the owner of the IRP. If the thread that happens to be running (a user thread? a system thread? do you even know?) when you call IoBuildXxxx exits, aborts, or in some other way terminates, the IRP that you’ve issued gets cancelled. It is unlikely in the extreme that this is the behavior that you want. You are building this IRP on behalf of your driver, to do work that your driver needs to do, not on behalf of the current thread (to do work the current thread needs done).

Mr. Roberts, Mr. Grig and I have been doing this stuff a long time. I’d venture to say that between us we have more than 40 years of experience writing Windows drivers. We’re trying to advise you, but it feels like you’re fighting us.

Allocate the IRP with IoAllocateIrp, like I suggested a few days back. You’ll be happier in the end, and you’ll avoid all sorts of latent problems that your testing probably won’t detect and that you’ll have trouble diagnosing when you’re driver is in the field.

Peter
OSR
@OSRDrivers

Hi Peter,

Not at all! Quite the contrary in fact, and I’m a bit surprised to find that my tone is coming across as contradictory. I am simply trying to match what you guys are saying with what the documentation says. A direct quote from the microsoft article: “Handling IRPs: What Every Driver Writer Needs to Know” page 19:

Drivers can create two types of IRPs:
* Threaded IRPs, also called synchronous requests
* Nonthreaded IRPs, also called asynchronous requests

This article is what I based my design on, although I realise now that the issue is more complicated.

Driver writing only makes up about 5% of my work, and all of that has to come from self teaching. So my questions are based more from wanting to learn the correct way rather than just disagreeing because I don’t want to redo my work.

So please don’t think I’m not appreciating the input you guys are giving me!
Cheers
BJW

On, not “contradictory” at all! Rather it simply felt like you were very determined to use these threaded IRPs when we were consistently telling you that you didn’t need to.

And now I know why.

I thank you for providing the title to and quoting that article. That article is very, very, depressingly, hideously, and embarrassingly wrong. Please erase everything you read in it from your memory.

The people who write White Papers like the one you cited are not the same people as those who write the Windows Driver Kit documentation. The quality and accuracy of those papers varies widely. Some are great and show terrific insight. Most are OK, if lacking in practical insight. Some are truly terrible.

It seems you found one of those that are truly terrible.

As soon as I finish this post, I’m going to send a note to a colleague at Microsoft and begging to have it removed.

In any case… please don’t hesitate to continue to ask questions here. We’re happy to help. And I’m PARTICULARLY happy to know about that White Paper.

Peter
OSR
@OSRDrivers