Operation could destabilize the runtime – Reflection.Emit and common pitfalls

In the last post i said about LinqtExtender implementing necessary property and injecting specific settings for entity objects. The issue i have is that it works fine under full / high trust settings but when running in medium trust it gives the following error:

image

Ouch.. it is only happening while i am using the extender from medium trust environment. As to add a little prologue, actually it creates a proxy around your original entity and if you look closely it is giving the error in .ctor(). Now lets dig in.

   1: ILGenerator ilGenerator = constructorBuilder.GetILGenerator();
   2:  
   3: ConstructorInfo baseConstructor = typeof(object).GetConstructors()[0];
   4:  
   5: ilGenerator.Emit(OpCodes.Ldarg_0);
   6: ilGenerator.Emit(OpCodes.Call, baseConstructor);
   7: ilGenerator.Emit(OpCodes.Ret);

The IL code is pretty simple actually , its the method body of the proxy class constructor that calls default constructor of the base class. Now, this will work fine in full/high trust as here i require the entity class to have a default constructor. But, as i switch the mode to medium trust it will throw me the above exception. The reason why, in medium trust the framework verifies the IL generated and though it may seem from my point of view that its a valid IL as it is expecting default constructor , to framework’s context its invalid as the base object might never have any default constructor (it should throw error in high trust). In that case the call is absolutely suspicious duh…

So the valid block for this scenario would be:

   1: ILGenerator ilGenerator = constructorBuilder.GetILGenerator();
   2:  
   3: ConstructorInfo baseConstructor = null;
   4: ConstructorInfo[] constructorInfos = parent.GetConstructors();
   5:  
   6: bool containsDefaultConstructor = false;
   7:  
   8: foreach (ConstructorInfo info in constructorInfos)
   9: {
  10:     if (info.GetParameters().Length == 0)
  11:     {
  12:         baseConstructor = info;
  13:         containsDefaultConstructor = true;
  14:         break;
  15:     }
  16: }
  17:  
  18: if (!containsDefaultConstructor)
  19:     throw new Exception(Properties.Messages.MustHaveADefaultConstructor);
  20:  
  21: ilGenerator.Emit(OpCodes.Ldarg_0);
  22: ilGenerator.Emit(OpCodes.Call, baseConstructor);
  23: ilGenerator.Emit(OpCodes.Ret);

The code is similar , just it checks for a default constructor , if not throws a valid exception and to medium trust everything looks fine.  I have added a patch for extender with this as well, do check it out.

Finally, while you are doing Reflection.Emit do check this and more like, you should not emit any unmanaged code and even not play around with private stuffs , etc to avoid pitfalls.

Hope that helps

Shout it

No Comments