MDA: Callback On Garbage Collected Delegate

June 11, 2010

no comments

One day I’m going to write a long, detailed post about an incredible tool called Managed Debugging Assistants (MDAs). But today is not that day. Instead, I would like to ignite your interest in MDAs by showing you how they immediately make obvious a non-trivial debugging scenario.

Oren writes:

[…] if you run [this code] on a background thread and continue to do additional operations […] it will crash, sometimes with a null reference exception, sometimes with attempt to write to protected memory, etc.

There is a very subtle bug here, can you figure out what it is?

Luckily, this bug is not subtle enough to escape automatic detection. But first things first. I wrote a simple test case that is fairly similar in spirit to the bug Oren is referring to. Then, I ran the executable and received the following exception:

image

An access violation, all right, but what’s the precise location that caused the problem? The DoWork method is a P/Invoke call, but is it responsible for the memory corruption?

Opening the application’s crash dump yields the following call stack for the crash:

0:000> kn
0x120b92
NativeDll!DoWork+0×41 [nativedll.cpp @ 10]
0x3d0195
clr!CallDescrWorker+0×33

0:000> u 00120b92
00120b92 0000            add     byte ptr [eax],al
00120b94 0000            add     byte ptr [eax],al
00120b96 0000            add     byte ptr [eax],al
00120b98 9f              lahf
00120b99 f79d6a286a00    neg     dword ptr [ebp+6A286Ah]
00120b9f 1c01            sbb     al,1
00120ba1 0000            add     byte ptr [eax],al
00120ba3 0000            add     byte ptr [eax],al

The function invoked by DoWork looks like a random bunch of assembly instructions… It’s not immediately evident from what we’ve seen so far where the culprit lies. However, let’s see what happens if we run the application from within Visual Studio, with the debugger attached:

image

Visual Studio hands us the error on a silver platter—or, to be specific, the CallbackOnCollectedDelegate MDA hands us this bug. This is an automatic diagnostic tool that pops up in the middle of your debugging session and shows you the error of your ways. It appears that the delegate must be kept alive until the underlying P/Invoke call is done—if the delegate is garbage collected and a call is attempted through it from unmanaged code, havoc ensues.

CallbackOnGarbageDelegate has many other MDA friends lurking in the Visual Studio “Exceptions” dialog. You can enable and disable MDAs during your Visual Studio debugging session, or in advance using a special configuration file.

As I said, I’m looking forward to writing a couple more posts on MDAs. Until then, you might find the following resources useful:

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>