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.

有帮助吗?

解决方案

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.

其他提示

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.

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top