Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Marshal.GetFunctionPointerForDelegate work on instance members?

I am wondering about Marshal.GetFunctionPointerForDelegate. Namely I want to know how it converts a delegate to a function that is non static into a function pointer.

Does it dynamically generate a code stub that has the instance attached somehow? And if so, doesn't this leak memory? Perhaps the delegate frees it in its finalizer?

It doesn't look like System.Delegate has a finalizer, so I am very interested in how this mechanism works. I would assume that it would take 4 bytes for the function pointer and 4 bytes for the instance (on 32-bit), yet it returns a simple IntPtr.

like image 685
jakobbotsch Avatar asked Dec 15 '13 22:12

jakobbotsch


1 Answers

Big question, delegates have an iceberg of code associated with them in the CLR. So just some hints. Download the SSCLI20 distribution to look at the source. All relevant code is in the clr/src/vm subdirectory.

UMEntryThunk is the wrapper for a thunk that marshals the call. It is created by COMDelegate::ConvertToCallback() in comdelegate.cpp, called by MarshalNative::GetFunctionPointerForDelegateInternal(), the internal implementation of the Marshal method.

A pointer to UMEntryThunk is stored in the syncblk for the delegate object, syncblk.h, InteropSyncBlockInfo::SetUMEntryThunk() method.

When the garbage collector destroys the delegate object, it also cleans up the syncblk for it and that invokes the ~InteropSyncBlockInfo destructor. Which calls the UMEntryThunk::FreeUMEntryThunk() method which cleans up the thunk again.

So, no, there is no memory leak. Not exactly a finalizer, just part of the normal GC cleanup.

like image 61
Hans Passant Avatar answered Sep 22 '22 20:09

Hans Passant