[Mono-list] Deep Marshaling

Jonathan Pryor jonpryor at vt.edu
Sun Oct 23 21:25:08 EDT 2005


On Sun, 2005-10-23 at 21:09 +0200, Giuseppe Greco wrote:
> Another alternative would be the following:
> 
> [StructLayout(LayoutKind.Sequential)]
> internal struct MyStruct
> {
>       public int Id;
>       public unsafe byte* Data;
> }
> 
> public unsafe void FillMyStruct(string s)
> {
...
>           pMyStruct->Data = pData + sizeof(int);
>           UnsafeCopy(
>               pData, 0,               // source buffer
>               pMyStruct->Data, 0,     // destination buffer
>               data.Length);           // number of bytes to copy
>       }
> }
>
> public static unsafe void UnsafeCopy(
>      byte* pSource, int sourceOffset,
>      byte* pDest, int destOffset, int count)
> {
>      byte* ps = pSource + sourceOffset;
>      byte* pd = pDest + destOffset;
...
>      int c = count / sizeof(long);
>      for (int i = 0 ; i < c; i++) {
>          *((long*)pd) = *((long*)ps);
>          pd += sizeof(long);
>          ps += sizeof(long);
>      }
...
> That works fine and performance is quite good. Of course,
> the method UnsafeCopy() is really 'unsafe', but it defined
> in an internal class...

Are you sure this works fine?  The source and destination buffers passed
to UnsafeCopy() overlap, and not in a good way:

        | 00  04  08  0C  0F  ...
           ^   ^
           |   pMyStruct->Data (destination)
           pData (source)

>From my reading of UnsafeCopy(), it will copy data.Length bytes from
source to dest in a "left-to-right" fashion.  Which means that once you
copy more than 4 bytes, you've overwritten the data you're supposed to
be copying...

What you really need is a std::copy_backward() implementation, copying
in a right-to-left fashion.  That way your source buffer won't be
overwritten before it's needed...

See also the difference between memcpy(3) (which doesn't handle
overlapping buffers) and memmove(3) (which does).

 - Jon




More information about the Mono-list mailing list