Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Reflection.Emit assign incompatible types?

I have two simple classes.

public class A { }
public class B { }

I build and instantiate class C like below.

var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Some.Namespace"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyBuilder.GetName().Name);

// public class C
var typeBuilder = moduleBuilder.DefineType("C", TypeAttributes.Public | TypeAttributes.Class, typeof(object));

// public A A;
var aField = typeBuilder.DefineField("A", typeof(A), FieldAttributes.Public);

// public C() { this.A = new B(); } !!!!
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
var ctorIL = ctorBuilder.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Newobj, typeof(B).GetConstructor(Type.EmptyTypes));
ctorIL.Emit(OpCodes.Stfld, aField);
ctorIL.Emit(OpCodes.Ret);

// return new C();
var type = typeBuilder.CreateType();
return Activator.CreateInstance(type);

The problem is I can successfully instantiate class C. When I check the type and value of C.A it was very surprising for me.

var c = CreateC();

var field = c.GetType().GetField("A");
var fieldValue = c.GetType().GetField("A").GetValue(c);

Console.WriteLine(typeof(A) == field.FieldType);      // True
Console.WriteLine(typeof(A) == fieldValue.GetType()); // False
Console.WriteLine(typeof(B) == field.FieldType);      // False   
Console.WriteLine(typeof(B) == fieldValue.GetType()); // True

Briefly, I have following classes which are working!

public class A { }
public class B { }

public class C 
{
    public A A;
    public C() 
    {
        this.A = new B();
    }
}

My questions are:

  1. How can this be possible?
  2. At which level does CLR checks the types?
like image 283
Mehmet Ataş Avatar asked Oct 19 '22 07:10

Mehmet Ataş


1 Answers

If your code runs under full trust, then the CLR doesn't bother checking that the IL is "verifiable". This means that the code can do all sorts of crazy things, and it's your responsibility to make sure the code you emit is type safe.

However, if your code runs under partial trust, then Activator.CreateInstance(type) will throw System.Security.VerificationException ("Operation could destabilize the runtime").

like image 58
Michael Liu Avatar answered Nov 15 '22 05:11

Michael Liu