I am allocating some unmanaged memory in my application via Marshal.AllocHGlobal. I'm then copying a set of bytes to this location and converting the resulting segment of memory to a struct before freeing the memory again via Marshal.FreeHGlobal.
Here's the method:
public static T Deserialize<T>(byte[] messageBytes, int start, int length)
where T : struct
{
if (start + length > messageBytes.Length)
throw new ArgumentOutOfRangeException();
int typeSize = Marshal.SizeOf(typeof(T));
int bytesToCopy = Math.Min(typeSize, length);
IntPtr targetBytes = Marshal.AllocHGlobal(typeSize);
Marshal.Copy(messageBytes, start, targetBytes, bytesToCopy);
if (length < typeSize)
{
// Zero out additional bytes at the end of the struct
}
T item = (T)Marshal.PtrToStructure(targetBytes, typeof(T));
Marshal.FreeHGlobal(targetBytes);
return item;
}
This works for the most part, however if I have fewer bytes than the size of the struct requires, then 'random' values are assigned to the last fields (I am using LayoutKind.Sequential on the target struct). I'd like to zero out these hanging fields as efficiently as possible.
For context, this code is deserializing high-frequency multicast messages sent from C++ on Linux.
Here is a failing test case:
// Give only one byte, which is too few for the struct
var s3 = MessageSerializer.Deserialize<S3>(new[] { (byte)0x21 });
Assert.AreEqual(0x21, s3.Byte);
Assert.AreEqual(0x0000, s3.Int); // hanging field should be zero, but isn't
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
private struct S3
{
public byte Byte;
public int Int;
}
Running this test repeatedly causes the second assert to fail with a different value each time.
EDIT
In the