A few posts ago I talked about a situation in which the finalizer thread is being blocked by a switch to an STA apartment when we are disposing an STA COM object without calling Marshal.ReleaseComObject.

In that post, I suggested using the sieextpub.dll debugger extension and call its !comcalls command that shows us which COM call is headed to which thread.

I just got an Email from Herve Chapalain (Herve, please let me know if you have a link that you want me to put here, or your Email address) about another way of getting the STA thread to which we are going to without using sieextpub.dll.

The method involves understanding the memory structure of a structure called OXIDEntry which, as far as I know (please correct me if I’m not) is an internal struct and does not appear in public symbols.

Fortunately, Herve is familiar with its memory layout and gave us the necessary offsets to use.

We first need to see the native stack of the finalizer thread (or in a case that we are not talking about a blocked finalizer thread and just want to find a deadlock regadless of .NET, the thread that is blocked) using the one of k commands.

The output should look something like this.
Notice that the call stack contains the GetToSTA call which means we do want to switch to the right STA thread that our object was created in.

We then take the 3rd parameter of the function “ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall” (you will see it in the call stack).
In Herve’s sample the address is 0016f6f4.

Next, we use the dd command to dump the memory at that address and we should be getting this:

0:005> dd 0016f6f4

0016f6f4 774a2328 774a22f8 00000003 0000002a
0016f704 001f5790 00000000 0016eec0 0016f978
0016f714 0017a120 01cca3e8 774a1930 00070005
0016f724 00000003 00000e54 00000000 004c0002
0016f734 000c01e0 0016f4d8 00150178 000201f5
0016f744 000801ee 00000000 0000000c 00000005
0016f754 00000000 00000000 0016f3b8 00171040
0016f764 0016eec0 0000b400 0e54086c c6a4049a

We need to take the 3rd value on the second line (its mared in bold) and run dd on it as well (this is, probably, a pointer inside the OXIDEntry structure):

0:005> dd 0016eec0
0016eec0 0016ef38 775c6fa0 0000086c 00000e54
0016eed0 d3b9b1cc ca2488ab b5ad2644 88cf2210
0016eee0 b5ad2644 88cf2210 0000b400 0e54086c
0016eef0 c6a4049a 49cd531e 00000103 004a02e6
0016ef00 0015a580 00000000 00000000 00000000
0016ef10 00000001 ffffffff 0016ee08 0150803c
0016ef20 00000006 00000000 00000000 00000000
0016ef30 00000000 00070005 0016efb0 0016eec0

Now we got the process id which is 86c and the thread id which is e54 (they are both marked in bold).

This means we are trying to move to thread e54 because that is where our STA COM object was created. In this sample, e54 is the main thread.

It’s a bit trickier, but if you know your offsets you can find it in no time and it’s very useful if you forgot to download sieextpub.dll or you are not able to install it at a customer site due to various limitations.

Thanks again for Herve for sending this information.

  • Michael Stanton

    Thanks, that came in real handy.
    I used to work on sos.dll at Microsoft, now I am “outside the borg” and needed to figure out which thread was the STA. Your dd commands saved the day. later!
    –Michael

  • Thanks Michael!

    It’s always nice to see that the information I post here actually help people 🙂

  • Steph

    Hey, thanks, a year later and this just did what SIEExtPub hasn’t been able to do on WOW64.

    Now I just gotta figure out why the callback is stuck calling on the proper thread, with a proper message loop going. Peanuts.

  • Steph, I’m glad to hear that this still helps people 🙂

    You shouldn’t go down too much on SIEExtPub, after all, most people cannot get updated versions of this dll and the versions that do exists out there are really old and without much features.

    I just hope we can find someone in MS that will tell us what’s up with SIEExtPub and will there be additional releases for it, like they did with PSSCor.dll which turned out to be the newer version of sos.dll for .NET 1.1 that are shipping with WinDbg.

  • Steph

    Eran,

    Just fired off a query to a contact at Microsoft. Currently doing a job for a largish customer, might as well use the contacts we’re given 🙂

    I’ll let you know if anything comes out of this.

  • Steph,

    That’s really great. I hope we can all get our hands on a new, updated and feature reach SIEExt 🙂

  • guest

    Nice, this method worked when !comcalls didn’t

  • Very useful post. I am really impressed and I have tried it sucessfully. Dumping the memory by the dd command is a little bit complicated. Thanks a lot for sharing this with all of us. It was really helpful to find STA thread.

  • Thanks for sharing this with us. It was really helpful to find this.

  • MoA

    Man i have been looking all over for this info. I’m not a wiz at memory structure so this def helps me out! Thanks again!!!

  • Anonymous

    Glad I could help.

  • Just what I am looking for a long time. Great post.That really helps me to find STA thread!

  • LinkUP

    Linkup.com.ua
    It helps me!!thnx

  • Ron Inbar

    I tried both methods. !comcalls gave me some strange numbers that I couldn’t read (plus it says the TID might be junk).
    0:184> !comcalls
    Thread 5 – MTA
    Target Process ID: 10ac0f38 = 279711544
    Target Thread ID: c3e58693 (STA – Possible junk values)
    The 2nd method worked very nicely and gave me a PID and TID I could use.
    Thanks!

  • It’s realy works, thanks!