Oh that Hurts, How to use IoForwardIrpSynchronously
OSR Staff | Published: 15-May-03| Modified: 16-May-03
Have you ever seen a function in the DDK and used it without reading the documentation carefully and thinking about what it means? Well that is what happened to me today.
I was writing a routine to create an Irp and send it synchronously to another driver. So I called IoAllocateIrp with the appropriate number of stack locations and set up the fixed part of the Irp. Next, I called IoGetNextIrpStackLocation() so that I could set up the stack for a IRP_MJ_INTERNAL_DEVICE_CONTROL request for the driver that I was sending the Irp to. So far so good.
Since I wanted to wait for the Irp being sent to the next driver to complete, I was about to implement my own waiting mechanism when I decided to save myself some code and call IoForwardIrpSynchronously. IoForwardIrpSynchronously is a new function that is available in Windows XP and later systems. This routine sends an IRP to a specified driver and waits for that driver to complete the Irp. Here is the function prototype:
IN PIRP Irp);
The comments in the Microsoft DDK for this routine state:
Use the IoForwardIrpSynchronously routine to synchronously forward the current IRP to the next driver in the stack. (To asynchronously forward the IRP, use the IoCopyCurrentIrpStackLocationToNext, IoCallDriver, and IoSetCompletionRoutines)
The IoForwardIrpSynchronously routine copies the current stack location to the next stack location. That stack location is then used as the current stack location by the driver specified in DeviceObject. If no next stack location is available, the routine returns FALSE. If the routine returns TRUE, then the IRP has been sent to the specified driver, and that driver has completed its processing of this IRP.
Now maybe this explanation, read carefully, would have tipped you off. But I hadn't consumed my prerequisite 5 large cups of coffee by 7:00 am so I was still a little fuzzy. Anyway... I compiled my code, started to test, and the strangest thing happened; Instead of showing up in the target drivers IRP_MJ_INTERNAL_DEVICE_CONTROL handler I showed up in its IRP_MJ_CREATE handler! Thankfully, I was in the debugger at the time that this happened and I examined the IRP using the WinDbg "!Irp" command.
1: kd> !Irp 81a11008
Irp is active with 2 stacks 2 is current (0x81a1109c)
No Mdl Thread 81bcada8: Irp stack trace.
cmd flg cl Device File Completion-Context
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
>[ 0, 0] 0 e0 81abe2e0 00000000 80523792-f9e79aac Success Error Cancel
Args: 00000000 00000000 00000000
If you notice both stack locations have "0" as the major function code. So I guess the I\O Manager was correct in calling the IRP_MJ_CREATE handler. The question is how did "0" get there? Well, I went back and desk checked my code and decided that there was nothing obviously wrong. Heck, I’ve done this type of thing 100s of times! The only thing different this time was that I called IoForwardIrpSynchronously instead of doing the synchronous stuff myself. Soooo, I went back to the documentation…
Well, the answer was in the 2nd paragraph of the documentation, "The IoForwardIrpSynchronously routine copies the current stack location to the next stack location". Duh! As you may have noticed after I allocated the Irp, I called IoGetNextIrpStackLocation. This would have been the correct thing to do if I was going to call IoCallDriver myself. So, I was copying a non-existant stack location to the next stack location.
How to fix this? Well, since I was using IoForwardIrpSynchronously, you might think that you could call IoGetCurrentIrpStackLocation and set up that stack location (because IoForwardIrpSynchronously copies the current IRP stack location to the next IRP stack location). Well, that doesn't help, because the current stack location is still invalid!
So, what's the answer? Well, the answer is to allocate the IRP, and then call IoSetNextIrpStackLocation before you call IoGetCurrentIrpStackLocation. This will make the next Irp Stack location the current Irp stack location. Oh, and remember that when you allocate the Irp, you need to make sure that there are at least 2 stack locations in the Irp.
Hmmmm... Maybe that's why they named this DDI "IoForwardIrpSynchrnously" instead of "IoCallDriverSynchronously". Ah, now it's all clear...
It's worth noting that if I had been using either CUV (Call Usage Verifier) or Driver Verifier at the time, I would have gotten an immediate error. Verifier would have bugchecked with a DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION stop code because there is no Current stack location for an Irp that you just allocated. CUV will break into WinDbg with a very explicit message"The next stack location in the IRP specified as parameter num [0xaddress] is not valid.".
Gee, I guess I should have used those tools, like I tell people to, huh?
So, keep this in mind if you decide to use IoForwardIrpSynchronously to send an Irp that you have created to another driver.
Rate this article and give us feedback. Do you find anything missing? Share your opinion with the community!
Post Your Comment