3

I have a struct which has a non-overlapping field reported as overlapped.

[FieldOffset(8)]
Int32 X;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
[FieldOffset(12)]
string Y;

[FieldOffset(28)]
int Z;

The reported error is:

Could not load type 'XXX' ... it contains an object field at offset 12 that is incorrectly aligned or overlapped by a non-object field.

It occurs only in Release configuration (TRACE, DEBUG flags and unsafe code are enabled, optimization is turned off), guessing - what happens to it?

UPD: thanks to @svick. Confirmed that x64 build is not what one wants for marshalling.

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
kagali-san
  • 2,964
  • 7
  • 48
  • 87
  • Are you specifying the charset in the StructLayout attribute? As in http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.charset.aspx ? If not I suppose there could be some weird switching of charsets between builds as that structure would be correct with single byte characters but not wide characters – tyranid May 05 '12 at 11:23
  • Can you use `LayoutKind.Sequential` instead of `LayoutKind.Explicit`, and drop the `FieldOffset` attributes? It's not always possible, but if it's possible for you in this case, it may avoid the entire problem. –  May 05 '12 at 12:46

3 Answers3

5

First, Release configuration has nothing to do with this. What affects it is Platform Target: if you set it to x64, you will get this exception, but if you set it to x86, it will work fine.

I think the reason for this behavior is that FieldOffset is used to specify the layout of the struct in the managed memory (even if the documentation doesn't say this), but MarshalAs is not used in managed memory.

Because of this, the object in managed memory contains a reference at offset 12. And since all references have to be aligned in .Net (to 4 bytes in 32-bit application and to 8 bytes in 64-bit), you get the exception if you run your application as 64-bit.

So, the problem is not that you have overlapped fields, it's the other part of the error message: the field is incorrectly aligned.

The easy workaround is to compile the application as x86. If that's not possible for you, I'm not sure how to fix this.

svick
  • 236,525
  • 50
  • 385
  • 514
5

Annotating @svick's correct answer, the problem here is that your structure declaration violates the hard promise that the CLR makes that object assignments are atomic. That cannot work in 64-bit mode, with an offset of 12 the object pointer can straddle the end of a cache line. Accessing such a misaligned member always requires two reads or writes and that can never be atomic. I think it is actually a bug in the CLR type verifier but that's not going to help you get past this hump.

Surely you are doing this to interop with 32-bit code and you correctly changed the Platform target setting for the Debug build but forgot to do so for the Release build. It is a per-config setting. Easy fix, just change the setting for the Release configuration as well.

If you really need this to work in 64-bit mode then you need to declare it as fixed char[16] instead.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

I think default alignment of data fields in your system 8 bytes. You must use offset 16 for Y.

FiftiN
  • 740
  • 1
  • 7
  • 27