[Mono-list] Hang on JIT-ing fn with P/Invoke?

Jonathan Pryor jonpryor at vt.edu
Thu Aug 9 10:58:02 EDT 2007


On Thu, 2007-08-09 at 14:01 +0100, Andy Hume wrote:
> There may well be something wrong with the P/Invoke definitions :-,),

I have no idea why it's hanging, but the P/Invoke definitions *are*
wrong:

>     [StructLayout(LayoutKind.Sequential)]
>     class uuid_t
>     {
>         public byte type;
>         public Guid uuid128; //?
>     }
> 
>     [StructLayout(LayoutKind.Sequential)]
>     class sdp_list_t
>     {
>         public sdp_list_t next;
>         public IntPtr data;
>     }
> 
>     class NativeMethods
>     {
>         const string BluetoothLibrary = "libbluetooth";
> 
>         //sdp_list_t* sdp_list_append(sdp_list_t* list, void* d);
>         [DllImport(BluetoothLibrary)]
>         internal static extern sdp_list_t sdp_list_append(sdp_list_t list, uuid_t d);
> 
>         //uuid_t* sdp_uuid16_create(uuid_t* uuid, uint16_t data);
>         [DllImport(BluetoothLibrary)]
>         internal static extern uuid_t sdp_uuid16_create(uuid_t uuid, Int16 data);
> 
>     }

Never use reference types as the return value of a P/Invoke (in this
case, both sdp_list_t and uuid_t are reference types, as you declared
them `class', not `struct').  The reason for this is that the runtime
will allocate a class instance on the GC heap, copy over the
class/structure contents, and free the returned memory [1].  This is
almost *never* what you want, as the memory may (probably will) be freed
by the wrong function, thus corrupting the heap.  Not good.

The correct thing to do is to use IntPtr as the return value, and
marshal the IntPtr into the appropriate type using
Marshal.PtrToStructure().

So a more accurate binding would be:

        struct BluezUuid {
                public byte type;
                public Guid uuid128;
        }
        
        static class NativeMethods {
                const string BluetoothLibrary = "libbluetooth";
                
                // sdp_list_t* sdp_list_append(sdp_list_t* list, void*
                d);
                internal static extern IntPtr sdp_list_append(IntPtr
                list, 
                	IntPtr d);
                
                // uuid_t* sdp_uuid16_create(uuid_t* uuid, uint16_t
                data);
                internal static extern IntPtr sdp_uuid16_create(
                        ref BluezUuid u, ushort val);
        }

With usage:

        IntPtr uuid = 
            UnixMarshal.AllocHeap(Marshal.SizeOf(typeof(BluezUuid));
        NativeMethods.sdp_uuid16_create(uuid, 0x0100);
        
        IntPtr search_list = NativeMethods.sdp_list_append(IntPtr.Zero,
            uuid);

Yes, this style of programming is horribly unsafe (IntPtrs everywhere!
No compiler-checked type safety!), but you need to conform to what the
existing code is expecting, in this case malloc(3)-allocated memory of
the appropriate size, with no inappropriate implicit marshaling.

 - Jon

[1]
http://www.mono-project.com/Dllimport#Classes_and_Structures_as_Return_Values





More information about the Mono-list mailing list