Monday, December 15, 2008

Dynamic method drop

Dynamic methods drove me crazy for the last two days. A completely innocent-looking, verified IL which created delegates from dynamic methods sometimes blew up with all kinds of exceptions: null-reference exceptions in weird places, stack overflows (or hang-ups if not running under Developer Studio) and the enigmatic FatalExecutionEngineError. Other times the code executed without a problem. It was difficult to establish any pattern in these failures. windbg+SoS revealed nothing beyond the fact that the IL was being generated correctly, and excavations of RedBits/Rotor code did not help much either. I went over the whole mess in my mind while listening to a jazz performance, and realized that the flaw was in my delegate-creation IL code, which went like this:

push target object
ldftn dynamic method
newobj Procedure..ctor(object, native int)
store new delegate

This code creates a working delegate, but the delegate's internal _methodBase field is initially null. The bald function pointer does not work as a GC reference, and if there are no other references to the dynamic method, it is liable to be garbage-collected, and the delegate containing the stale function pointer naturally but silently becomes a nest of nasal demons.

Delegate.CreateDelegate overloads don't fill _methodBase either. DynamicMethod.CreateDelegate does fill it explicitly, but it is impossible to get the DynamicMethod object from its token without calling mscorlib's internal methods. I understand the security reasons behind this decision, but it's damned uncomfortable.

The only solution to the problem I have found so far is to call the new delegate's get_Method() function to fill _methodBase and establish a GC-visible reference to the dynamic method. Whew!

Update: reported this issue to Microsoft; they decided to close it as a 'known limitation'. Well, it is known — now :3

No comments: