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.