Could 1 byte alignment cause memory corruption?

629 views Asked by At

Lets say you have a struct in C++ (using MFC, compiled 32 bit) that's defined like so:

#pragma pack (push, 1)
struct foo
{
   float f;
   int z;
   DWORD k;
   BYTE b;
   int i;
}; 
#pragma pack (pop,1)

Now you create a memory-mapped file using CreateFileMapping in Windows and then you write this structure's contents to this memory area. This is a globally accessible memory-map.

Now you have C# application (compiled 32 bit) and you create a structure similar to this:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct foo
{
   double f;
   int z;
   int k;
   byte b;
   int i; 
}

Now when C# reads the memory mapped data, it comes out as corrupted. If the type of f is double, as above, the values for this particular member are junk, the other members have correct content. If you change it to float, then all other members contain junk too.

My question, could it be that the 1 byte alignment is causing the reading of garbage?

Unfortunately I don't have the code that reads/writes to the memory map here, but the structure layout is as above.

If the alignment isn't an issue here, what could cause it to read junk? Tried to change the types of the various members around several times, makes no difference.

2

There are 2 answers

3
David Heffernan On BEST ANSWER

Looking at the two structures, they obviously differ in that the unmanaged starts with a float, and the managed starts with a double. Obviously that means that the structs do not match. The managed struct is 4 bytes longer, and all members after the first are offset by 4 bytes.

Now, you say that when you have the code as per the question, the first field contains garbage, but the other fields are fine. From which the only reasonable conclusion is that the write side of the interface is writing to an address offset by 4 bytes from that which the read side is reading.

Alignment and packing are not the issue here. You are reading from an address 4 bytes different from that which is used to perform the write.

The solution is to:

  1. Make sure that you write to and read from the same location in shared memory.
  2. Define your structs to be identical.
2
stonemetal On

It sounds like an alignment rather than packing. C# promises at least 4 byte alignment in 32 bit code so that updating 32 bit primitives is atomic. I wonder what would happen if you put two floats instead of a double for the first member.