1

Im messing arround with structlayouts and I found some thing i find quite odd:

The following code is working as i thought it would:

using System;
using System.Runtime.InteropServices;
public class Program
{
    [STAThread]
    static void Main()
    {
        Magic m = new Magic 
        { 
            InstanceA = new ClassA(), 
            InstanceB = new ClassB {Value="47"} 
        };

        Console.WriteLine(m.InstanceA.Value);
        Console.ReadKey();
    }

    class ClassA
    {
        public dynamic Value;
    }

    class ClassB
    {
        public string Value; // Change to int and it will get messy
    }

    [StructLayout(LayoutKind.Explicit)]
    struct Magic
    {
        [FieldOffset(0)]
        public ClassA InstanceA;
        [FieldOffset(0)]
        public ClassB InstanceB;
    }
}

However, if you change classB.Value to int, this code will throw the mentioned FatalExecutionEngineError.

Can anyone explain why or maybe how to workarround? I know this is probably way too complicated and im just messing arround here but someone might want some challenge.

CSharpie
  • 9,195
  • 4
  • 44
  • 71
  • That's a *really* bad thing to do *anyway*; overlaying references is ... gah. Why not just have one `object` field and two properties that cast that field? Also... mutable struct, public fields, etc ;p – Marc Gravell Nov 28 '14 at 20:25
  • You should only use explicit layout if you know exactly what you are doing. It is designed for unmanaged interop scenarios not "just messing around". See http://stackoverflow.com/q/23323696/517852. – Mike Zboray Nov 28 '14 at 21:06
  • What is designed for messing around then? ^^... I got what you are saying though. – CSharpie Nov 28 '14 at 21:13

1 Answers1

0

Basically, what you have done is completely undefined. You are tricking it in two very nasty ways:

  • by pretending that one non-null class reference is actually of a different type (but with this being done without a type-check)
  • by having it attempt to load an object reference (dynamic is just object with some fancy compiler tricks) from an int (note; in all cases this will most likely point to garbage; in the case of x64, it isn't even an entire width, so it will be reading garbage into the value to dereference

Basically: don't do that. This is incidentally why explicit layout is treated as unverifiable code. As for how to do it "properly" (and I use that term generously):

class Magic
{
    private object val;
    public ClassA InstanceA { get { return (InstanceA)val;} set { val = value; } }
    public ClassB InstanceB { get { return (InstanceB)val;} set { val = value; } }
}

You could also use val as Foo instead of the (Foo)val if you want to see null when it is the other type.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Well I was a bit too excited here with the dynamic keyword, I thought i could make some "private access" happen. – CSharpie Nov 28 '14 at 21:15