I tried to experiment with the ability of .NET to support unions using the code below, but it causes a System.ExecutionengineException in .NET 2.0 and FatalExecutionEngineError in .NET 4.0 with the message:
The runtime has encountered a fatal error. The address of the error was at 0x738b3138, on thread 0x1080. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
I agree that this code should not work, but I didn't expect this kind of exception. Is this a .NET bug?
Class POLine
Public price As Decimal
Public VendorItem As String
End Class
Class SOLine
Public price As Decimal
Public Required As DateTime
End Class
<System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)> _
Structure LineRef
<System.Runtime.InteropServices.FieldOffset(0)> _
Public poLi开发者_运维百科ne As POLine
<System.Runtime.InteropServices.FieldOffset(0)> _
Public soLine As SOLine
End Structure
Sub Main()
Dim lr As New LineRef
lr.poLine = New POLine With {.price = 1.23D, .VendorItem = "X22"}
lr.soLine = New SOLine With {.price = 3.14D, .Required = DateTime.Now}
Console.WriteLine("{0} {1}", lr.soLine.price, lr.soLine.Required)
Console.WriteLine("{0} {1}", lr.poLine.price, lr.poLine.VendorItem)
End Sub
Your code is unverifiable, since object references shouldn't overlap, which your poLine
and soLine
fields clearly do. As section 10.7 of Partition II of the ECMA CLI spec states:
Offset values shall be non-negative. It is possible to overlap fields in this way, though offsets occupied by an object reference shall not overlap with offsets occupied by a built-in value type or a part of another object reference. While one object reference can completely overlap another, this is unverifiable.
You can further check that your code is unverifiable using PEVerify (run peverify.exe against your executable from the Visual Studio command prompt) - it will confirm that the code contains an error.
Therefore it is not surprising that you see an exception at runtime, and the exception that you're seeing seems perfectly reasonable to me (the text indicates that it may be caused by unverifiable code) - what leads you to expect different behavior?
Changing the second field offset to 80 (or higher) will solve your problem.
Though I have no idea what all the structure layout and offsets are, what do you even use them for?
Edit: Oh just noticed your question is why it gives this error and not what causing it, and the 4.0 net says the error could be caused by corrupting the stack, and you declare a variable in the same offset as the first one which... corrupts the stack. There is no problem with that error.
You are mapping two reference types to the same offset. That by itself is not illegal as long as you don't try to use both at the same time, which is precisely what you are trying to do here.
It is not a bug, the usage you make of the union is simply wrong and the system rightfully complains. On a native environment, the pointer would have been silently overwrote.
精彩评论