3

In the following bit of code, I am observing that the marshaler is reading past the 3 byte source array to populate another 8 bytes of data. With time, the code eventually throws a memory access violation. Is there a way to tell the marshaller to only marshal the first 3 bytes when converting a pointer to a structure? If I make the Articulations array "NonSerialized" then the constructor will throw an access violation when processing a source array of 11 bytes.

using System;
using System.Runtime.InteropServices;

namespace MarshallingTest
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct Articulation
    {
        public const int BaseSize = 8;
        public byte attribute1;
        public byte attribute2;
        public byte attribute3;
        public byte attribute4;
        public byte attribute5;
        public byte attribute6;
        public byte attribute7;
        public byte attribute8;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class TestEntity
    {
        public const int BaseSize = 3;

        public byte EntityId;         //  1 byte
        public byte Variable;         //  1 byte
        public byte NumArticulations; //  1 byte

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct)]
        public Articulation[] Articulations;   // 8 bytes each

        public TestEntity(byte[] rawData)
        {
            unsafe
            {
                fixed (byte* pData = rawData)
                {
                    // I am observing that the marshaler is reading past the 3 bytes
                    // to populate another 8 bytes of data.  With time, the code
                    // will eventually throw a memory access violation.
                    //
                    // Is there a way to tell the marshaller to only marshal the 
                    // first 3 bytes when converting a pointer to a structure?
                    Marshal.PtrToStructure((IntPtr) pData, this);

                    for (int i = 0; i < BaseSize + Articulation.BaseSize; i++)
                    {
                        Console.WriteLine("pData + " + i + " = " + *(pData + i));
                    }
                }
            }
        }

        public byte[] ToRaw()
        {
            byte[] byteArray = new byte[BaseSize + Articulation.BaseSize*Articulations.Length];
            unsafe
            {
                fixed (byte* pData = byteArray)
                {
                    Marshal.StructureToPtr(this, (IntPtr) pData, false);
                }
            }
            return byteArray;
        }
    }

    internal class Program
    {
        private const int TestDataSize = TestEntity.BaseSize;

        private static void Main()
        {
            byte[] testData = new byte[TestDataSize];
            for (int i = 0; i < TestDataSize; i++)
            {
                testData[i] = (byte) (i + 1);
            }
            TestEntity test = new TestEntity(testData);

            // Print resulting array.  You'll see that data outside the source
            // byte array was marshalled into the test structure.
            Console.WriteLine(test.EntityId);
            Console.WriteLine(test.Variable);
            Console.WriteLine(test.NumArticulations);
            Console.WriteLine(test.Articulations[0].attribute1);
            Console.WriteLine(test.Articulations[0].attribute2);
            Console.WriteLine(test.Articulations[0].attribute3);
            Console.WriteLine(test.Articulations[0].attribute4);
            Console.WriteLine(test.Articulations[0].attribute5);
            Console.WriteLine(test.Articulations[0].attribute6);
            Console.WriteLine(test.Articulations[0].attribute7);
            Console.WriteLine(test.Articulations[0].attribute8);

            Console.WriteLine("Test complete.");
        }
    }
}
  • You could copy it to a temporary location that's large enough. – CodesInChaos Jun 07 '12 at 16:50
  • But why do you want to use such low level serialization? That's doesn't fit the .net way at all. I'd rather use reflection together with dynamic code generation. – CodesInChaos Jun 07 '12 at 16:51
  • @CodeInChaos, you wouldn't believe the speed increase that such methods can give you. Thin 10-100x less in CPU. He probably needs it. – usr Jun 07 '12 at 17:01
  • @CodeInChaos, I am trying to minimize the amount of memory being allocated and deallocated by the code. This code is a simplified example of a larger program that marshals billions of data packets received from a socket into an object, perform some modifications to the object, serializes the object back to a byte array, and sends the byte array through another socket. Performance is critical in this application. – Owen Funkhouser Jun 07 '12 at 17:31

0 Answers0