Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Exactly when does IRP_MJ_CLOSE get called?

309 views
Skip to first unread message

Just Another Victim of the Ambient Morality

unread,
Feb 16, 2000, 3:00:00 AM2/16/00
to
Okay, this is totally puzzling me and I'm hoping someone here can clear this
up.

I have two drivers, one of which is using the other. Let's call them driver
A and driver B.
Driver B opens a file to driver A using IoGetDeviceObjectPointer(). In a
thread (a work item, actually), B sends commands to A using
IoBuildDeviceIoControlRequest() and IoCallDriver(), in fact it does so
twice. Now because the use of the pointers to driver A (the device object
pointer and the file object pointer) are shared across different threads,
their access is protected by a mutex (the fast safe one). Also, because A
has resources allocated for each open file handle to it, I had to assign
irp->Tail.OriginalFileObject the pointer the file object returned by
IoGetDeviceObjectPointer() just before calling IoCallDriver().
My problem is this. The IRP_MJ_OPEN function for A gets called when I call
IoGetDeviceObjectPointer() and this is as I expect. However, after the two
calls to IoCallDriver() in the thread have been made, the thread then calls
ExReleaseFastMutex() and the IRP_MJ_CLOSE function for A gets called!
What?! I don't get it...
I've verified this by setting FsContext2 (FsContext1 is actually being used
for something) of the file object to something recognizable (0x00ABBA00, if
you remember them) and inserting an __asm int 3 in the IRP_MJ_CLOSE function
of A, since I wanted to step through the source code of B in SoftICE.
Indeed, IRP_MJ_CLOSE was being called with my ABBA file object created by
IoGetDeviceObjectPointer() in B just when an attempt to step over
ExReleaseFastMutex() in SoftICE was being made.
What happens (I believe) is that when the IRP_MJ_CLOSE function of A gets
called, it closes the file object that to it, that file is no longer valid.
However, B never called ObDereferenceObject() so it thinks the file object
is perfectly valid. The annoying bug that I've been hunting for far too
long is that since IoCallDriver() is such an amazingly light function (it
hardly does anything), B keeps feeding A the invalid file object pointer (it
has been deallocated by A's IRP_MJ_CLOSE function) and A uses it just fine
until that memory actually gets reallocated. In which case my page fault
comes up and I'm left wondering why.
So, what is happening here? Why is A's IRP_MJ_CLOSE function being called?
I didn't do anything to overtly close the file handle. How am I supposed to
use one driver from another?
Your help is _much_ appreciated.


Just Another Victim of the Ambient Morality

unread,
Feb 16, 2000, 3:00:00 AM2/16/00
to

Just to give you an upudate to my bug.

I've commented out the mutex calls in the thread (for debugging puposes
only, of course) and A's IRP_MJ_CLOSE function now gets called if you step
over or into the first IoCallDriver() call in the thread using SoftICE.

Oh, and I don't actually know if the file object is _actually_ being closed.
I only assumed that 'cause the IRP_MJ_CLOSE function was being called. The
IRP_MJ_CLOSE function is only called once, which is another indication that
the file has been closed.

keithmo

unread,
Feb 19, 2000, 3:00:00 AM2/19/00
to
Try setting a breakpoint on ObfDereferenceObject() instead.
ObDereferenceObject() (without the 'f') is only exported for legacy drivers
built back in the dark ages before this API became "fastcall". There's a
#define in ntddk.h to make this transparent.

KM

"Just Another Victim of the Ambient Morality"
<moc.re...@di--drawkcab.invalid> wrote in message
news:jpgr4.1557$CA2.1437@client...
>
> keithmo wrote in message
> <9W6r4.15645$Zp1.4...@newsread1.prod.itd.earthlink.net>...
> >The IRP_MJ_CLOSE is issued when the last reference to the FILE_OBJECT is
> >removed. Something is dereferencing your file object when you least
expect
> >it. Is your IRP completion routine calling ObDereferenceObject() on your
> >file object?
>
> Absolutely not!
> I don't have a completion routine 'cause, miracle of miracles, I don't
care
> when the routine completes and I don't care to do anything in response to
> it's completion (like a fire and forget missle). I checked my source and
> there's only _one_ place where ObDereferenceObject() is called, and that's
> in a function that's only called.
>
> Anyway, I put a breakpoint on the only call to ObDereferenceObject() and
it
> was never called but the IRP_MJ_CLOSE function was! So, I guess you're
just
> as stumped as I am. There must be another condition in which that
function
> is being called 'cause, after all, it's being called!
>
> Just in case some of you have some wild ideas about some silly mistakes I
> may have made, no, I didn't assign my close function to some other IRP_MJ
> function, just the closing one...
>
>
>
>
>

Just Another Victim of the Ambient Morality

unread,
Feb 20, 2000, 3:00:00 AM2/20/00
to

keithmo wrote in message ...

>Try setting a breakpoint on ObfDereferenceObject() instead.
>ObDereferenceObject() (without the 'f') is only exported for legacy drivers
>built back in the dark ages before this API became "fastcall". There's a
>#define in ntddk.h to make this transparent.

I don't understand what you're saying. It sounds like you're saying I
should put a breakpoint on ObfDereferenceObject() as if it were a different
function. In the DDK that I have, ObDereferenceObject() is a macro for
ObfDereferenceObject(). Could you please clarify what you mean?

Phillip Susi

unread,
Feb 21, 2000, 3:00:00 AM2/21/00
to
"Just Another Victim of the Ambient Morality" <moc.re...@di--drawkcab.invalid> writes:

He said that it is a macro for ObfDereferenceObject, which is the fastcall
version of the function. Therefore, you need to set the breakpoint on
that fastcall version, rather than on the normal ObDereferenceObject
function that is still exported from the kernel for compatability with
older code that still calls on the stdcall version.

Just Another Victim of the Ambient Morality

unread,
Feb 21, 2000, 3:00:00 AM2/21/00
to

keithmo wrote in message ...
>The kernel exports both ObDereferenceObject() and ObfDereferenceObject().
>The former uses the __stdcall calling convention, while the latter is
>fastcall. Any driver built with a reasonably modern NTDDK.H (like, anything
>post NT 3.1 if memory serves) will use ObfDereferenceObject().
>
>Set a breakpoint on ObDereferenceObject(), it will probably never get hit.
>Set a breakpoint on ObfDereferenceObject(), and it will get hit very
>frequently.

Okay, I understand what your saying but...
ObDereferenceObject() in the DDK that I'm using (in case there are others)
is just a macro for ObfDereferenceObject(). So, when I put a breakpoint on
ObDereferenceObject(), I'm really putting a breakpoint on
ObfDereferenceObject(), which is what I want. This is what was confusing me
about your suggestion and why I mentioned that it was a macro.

Now, it sounds like you're suggesting that I put a breakpoint _inside_ of
ObfDereferenceObject() so that _any_ attempt to decrement the reference
count of an object will hit the breakpoint. I'm not sure how to do this
since SoftICE will not let me step into a system call. Any suggestions?
Also, I'm wondering what I hope to accomplish by this. I mean, am I hoping
to see which part of my code is calling ObDerefereceObject()? I can already
tell you that _none_ of _my_ code is calling it since I put a breakpoint on
(in front of, really) the _only_ call to that function. If I'm calling it,
it's either from a system call that calls it (unlikely, since it would also
need the file object as a parameter) or the IO manager is calling it in
response to something I have done. Hence my question, exactly when does
IRP_MJ_CLOSE get called? There's obviously another way for the function to
get called other than ObDereferenceObject() 'cause I'm not calling this
function but the IRP_MJ_CLOSE function is still being called.

Just Another Victim of the Ambient Morality

unread,
Feb 21, 2000, 3:00:00 AM2/21/00
to
I have discovered the source of my problem but not why it is a problem.
If you recall, I was filling in the OriginalFileObject field of the IRP with
the file object before passing it to IoCallDriver(). This, somehow, is
causing the IO manager to close the file object.
I don't understand why this is. I was told that IoCallDriver was a really
light weight function. I was told that _all_ it does is decrement the IRP
stack pointer, call the dispatch routine, and ensures that the completion
routine gets called. That's it, so amazingly simple the function could have
been implemented as a macro.
So, why does this cause the IO manager to call my IRP_MJ_CLOSE function?

keithmo

unread,
Feb 22, 2000, 3:00:00 AM2/22/00
to
The kernel exports both ObDereferenceObject() and ObfDereferenceObject().
The former uses the __stdcall calling convention, while the latter is
fastcall. Any driver built with a reasonably modern NTDDK.H (like, anything
post NT 3.1 if memory serves) will use ObfDereferenceObject().

Set a breakpoint on ObDereferenceObject(), it will probably never get hit.
Set a breakpoint on ObfDereferenceObject(), and it will get hit very
frequently.


KM

"Just Another Victim of the Ambient Morality"

<moc.re...@di--drawkcab.invalid> wrote in message
news:jofs4.1237$Y87.1343@client...


>
> keithmo wrote in message ...

J. J. Farrell

unread,
Feb 22, 2000, 3:00:00 AM2/22/00
to
In article <zPzs4.1374$4m1.1472@client>,
"Just Another Victim of the Ambient Morality" <moc.rebircsni@di--

drawkcab.invalid> wrote:
>
> ObDereferenceObject() in the DDK that I'm using (in case
> there are others) is just a macro for ObfDereferenceObject().
> So, when I put a breakpoint on ObDereferenceObject(), I'm
> really putting a breakpoint on ObfDereferenceObject(), which
> is what I want. This is what was confusing me about your
> suggestion and why I mentioned that it was a macro.

Think about this more carefully - you're twisting it around.

The header which you're compiling your driver with uses a
macro to change your call to ObDereferenceObject() into a
call to ObfDereferenceObject(). Since it's in a header,
it's only relevant to the early stages of the C compiler,
long before any driver gets generated - it has no relevance
anywhere else. The effect is that when the compiler/linker
generates your driver, the driver contains calls to
ObfDereferenceObject() but no calls to ObDereferenceObject().

For historical reasons, the kernel libraries contain two
distinct functions called ObDereferenceObject() and
ObfDereferenceObject() - nothing about the DDK you use to
build your driver alters that. Your driver only contains
calls to ObfDereferenceObject(). When you set a breakpoint
on ObDereferenceObject(), you're setting one on a real
distinct function which your driver never calls.


Sent via Deja.com http://www.deja.com/
Before you buy.

Just Another Victim of the Ambient Morality

unread,
Feb 23, 2000, 3:00:00 AM2/23/00
to

J. J. Farrell wrote in message <88v49p$mpl$1...@nnrp1.deja.com>...

>In article <zPzs4.1374$4m1.1472@client>,
> "Just Another Victim of the Ambient Morality" <moc.rebircsni@di--
>drawkcab.invalid> wrote:
>>
>> ObDereferenceObject() in the DDK that I'm using (in case
>> there are others) is just a macro for ObfDereferenceObject().
>> So, when I put a breakpoint on ObDereferenceObject(), I'm
>> really putting a breakpoint on ObfDereferenceObject(), which
>> is what I want. This is what was confusing me about your
>> suggestion and why I mentioned that it was a macro.
>
>Think about this more carefully - you're twisting it around.

I think I know what you're saying and, in that case, I think I understand
where our confusion is.
You see, when I say I have a breakpoint on ObDereferenceObject(), I mean I
have a breakpoint on _the_call_to_ ObDereferenceObject(), so really, I have
the breakpoint in the right place (in that I acutally do know where the
breakpoint is). If fact, I _don't_know_ how to put a breakpoint into the
body of a system call. As I have said before, SoftICE doesn' t let me step
into a system call, so if there's something you know that I don't, please
share it with me.

So, does this change your view on my problem?


R.B. Talmadge

unread,
Feb 24, 2000, 3:00:00 AM2/24/00
to

Just Another Victim of the Ambient Morality
<moc.re...@di--drawkcab.invalid> wrote
>.As I have said before, SoftICE doesn' t let me step
> into a system call, >

If you mean ntoskrnl, that's odd, as it let's me do it.

rbt

Andy Grover

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
The crucial thing is that of (source, mixed, assembly) code viewing
mode, you cannot be in source mode and step in. Toggle modes by hitting
F3.

Regards -- Andy

--
----------------------------
Andy Grover
Intel/MCG/MTL
andrew...@intel.com
* I don't speak for Intel *

Maxim S. Shatskih

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
IRP_MJ_CLOSE is sent in ObDereferenceObject when reference count on
the file object drops to zero - be it explicit dereference, ZwClose or
process
rundown.
The function which sends IRP_MJ_CLOSE is called IopCloseFile - it is
registered as a "Close" method for "File" object type.

Max

Andy Grover <andrew...@intel.com> wrote in message
news:38C0624F...@intel.com...

Just Another Victim of the Ambient Morality

unread,
Mar 5, 2000, 3:00:00 AM3/5/00
to

Maxim S. Shatskih wrote in message <89ri3v$2gk$1...@gavrilo.mtu.ru>...

>IRP_MJ_CLOSE is sent in ObDereferenceObject when reference count on
>the file object drops to zero - be it explicit dereference, ZwClose or
>process
>rundown.
>The function which sends IRP_MJ_CLOSE is called IopCloseFile - it is
>registered as a "Close" method for "File" object type.


Well, then you might find this fact interesting.
I'm assuming you haven't been following this thread and, consequently, have
not read what I'm about to write, before. If you have, my apologies for
repeating myself.

What I was doing in my driver is getting a driver object and a file object
from IoGetDeviceObjectPointer() and building an IRP using
IoBuildDeviceIoControlRequest(). Since the second driver needs will
manipulate it's file object in it's dispatch routine, I figured I needed the
file object in the IRP somehow, so I put it (where else?) in
irp->Tail.Overlay.OriginalFileObject (please correct me if I got this
wrong). This caused the IRP_MJ_CLOSE function of the second driver on that
file object to be called.
Interesting, eh? What do you think?


Just Another Victim of the Ambient Morality

unread,
Mar 6, 2000, 3:00:00 AM3/6/00
to

Mark Roddy wrote in message ...
>On Sun, 5 Mar 2000 23:22:59 -0500, "Just Another Victim of the Ambient
>Morality" <moc.re...@di--drawkcab.invalid> wrote:
>[snip]

>
>
>> Since the second driver needs will
>>manipulate it's file object in it's dispatch routine, I figured I needed
the
>>file object in the IRP somehow, so I put it (where else?) in
>>irp->Tail.Overlay.OriginalFileObject (please correct me if I got this
>>wrong). This caused the IRP_MJ_CLOSE function of the second driver on
that
>>file object to be called.
>>Interesting, eh? What do you think?
>>
>I think you should put the fileobject in the next drivers
>IoStack.FileObject.

Oh, I didn't realize that that field existed (or that it was documented).
Okay, so I am to manipulate the appropriate stack location rather than the
IRP itself? It looks like the IO manager (or something) fills in the IRP
fields from the current IRP stack structure. I mean, this is where I
usually go to get and save file specific data in the dispatch routine. But
I was told that IoCallDriver() was a skeleton function. That is, it did
very little. It sounds like it does a little more than decrement the stack
pointer and call the dispatch routine, is this correct?

Or am I to look at the IoStack.FileObject field for my file object and never
touch the IRP itself?


Mark Roddy

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
On Sun, 5 Mar 2000 23:22:59 -0500, "Just Another Victim of the Ambient
Morality" <moc.re...@di--drawkcab.invalid> wrote:
[snip]


> Since the second driver needs will
>manipulate it's file object in it's dispatch routine, I figured I needed the
>file object in the IRP somehow, so I put it (where else?) in
>irp->Tail.Overlay.OriginalFileObject (please correct me if I got this
>wrong). This caused the IRP_MJ_CLOSE function of the second driver on that
>file object to be called.
>Interesting, eh? What do you think?
>
I think you should put the fileobject in the next drivers
IoStack.FileObject.

=
Mark Roddy
Independent WindowsNT/2000 Consultant
http://www.hollistech.com
mailto:in...@hollistech.com

Walter Oney

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
Mark Roddy wrote:
> On Sun, 5 Mar 2000 23:22:59 -0500, "Just Another Victim of the Ambient
> Morality" <moc.re...@di--drawkcab.invalid> wrote:
> [snip]
>
> > Since the second driver needs will
> >manipulate it's file object in it's dispatch routine, I figured I needed the
> >file object in the IRP somehow, so I put it (where else?) in
> >irp->Tail.Overlay.OriginalFileObject (please correct me if I got this
> >wrong). This caused the IRP_MJ_CLOSE function of the second driver on that
> >file object to be called.
> >Interesting, eh? What do you think?
> >
> I think you should put the fileobject in the next drivers
> IoStack.FileObject.

Right. This is an example of why it's often a bad idea to use
undocumented fields in system data structures or to drain the oil from
the engine of a running car. Setting OriginalFileObject earns you a
premature countdown of the reference count and deletion of the file
object. Someone is likely to blue-screen thereafter.

--
Walter Oney
http://www.oneysoft.com

Maxim S. Shatskih

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
> irp->Tail.Overlay.OriginalFileObject (please correct me if I got this

Wrong. This field is for internal IO manager's completion handler
(IopCompleteRequest) only. This is used to perform some cleanup actions
like unlocking the file object if it is opened for synchronous IO.
Use NextSp->FileObject instead.

Max

0 new messages