Problem with the OpenMAMA .Net layer
We came across a subtle (and interesting) issue in the .Net implementation. I’m going to describe the problem and how we worked around but I want to open it up for discussion before proposing any fixes. I’d also note that although we came across it in one particular context it is possible there may be similar cases elsewhere.
The Open MAMA .Net layer declares the getVectorAsString() method like this:
[DllImport(Mama.DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern int mamaMsgField_getVectorString (IntPtr nativeHandle,
ref IntPtr result,
ref uint size);
and the other vector-methods are similar. The functions that they are calling are declared in the C layer like this:
const mamaMsgField msgField,
const char*** result,
A problem arises in 64-bit Windows because sizeof(uint) != sizeof(mama_size_t) and this causes heap corruption, when the P/Invoke layer tries to marshal the values of result and size back to the C# code. The C code in the bridge writes size as a 64-bit value (because sizeof(mama_size_t) == 8), but the P/Invoke layer has allocated only 32-bits to hold it (because sizeof(uint) == 4, even in 64-bit Windows).
Our temporary workaround is as follows:
As it happens, the P/Invoke layer seems to assign the addresses of result and size next to each other in the heap, so we are able to avoid the problem by assigning to size first (overwriting the lower 32-bits of result) and then assigning the value of result afterwards. This is a horrible solution and is not acceptable for the longer term, though, as we would be relying on undocumented behaviour of the P/invoke marshaller, and any changes to the bridge implementation of the field-handling code may break it again.
We think a reasonable solution is to declare the size argument in the .Net getVectorAsString as ‘ref IntPtr’ rather than ‘ref uint’ which should guarantee the correct byte length on both 32 bit and 64 bit systems, but we are very interested to hear what other people think about this both in terms of the solution and our understanding of what the p/Invoke implementation is doing. Our analysis is based on inference from stepping the disassembled code J