Home > Open Source, Projects > Modelshredder: Tracking down InvalidProgramException

Modelshredder: Tracking down InvalidProgramException

I received my first bug report for modelshredder the other day. When trying to convert a sequence of objects into a DataTable, the following exception occurred:

I did some immediate research on possible causes for such an exception to be thrown. Microsofts KnowledgeBase indicated there might be a problem with the amount of local variables being allocated inside the injected method, however this was not the case since modelshredder uses only three local variables, regardless of the type of object. After some back and forth with the bug reporter, we were able to conduct a sample to reproduce the bug. Some trial and error with ShredderOptions including different subsets of members revealed, that the exception only occurred when the injected code tried to access an Indexer Property. The cause for this is pretty clear when taking a look at the MSIL generated for a property access.


ilgen.Emit(OpCodes.Ldloc_0);     // Load array on evaluation stack
ilgen.Emit(OpCodes.Ldc_I4_S, i); // Load array position on eval stack
ilgen.Emit(OpCodes.Ldarg_0);     // Load ourselves on the eval stack
ilgen.Emit(OpCodes.Call, pi.GetGetMethod());
// Check if we need to box a value type
if (pi.PropertyType.IsValueType)
{
    ilgen.Emit(OpCodes.Box, pi.PropertyType);
}

// Store value in array, this pops all fields from eval stack that were added this for loop
ilgen.Emit(OpCodes.Stelem_Ref);

As you can see, the code expects the getter to be callable without any parameter, which is not the case if (PropertyInfo) pi.GetGetMethod() returns an indexer method. Since I can’t imagine there’s any use in representing the contents of an indexer property in tabular form, I decided to simply ban indexer properties from the ShredderOptions. To do so, I have added a validation inside the ShredderOptions constructor to check all PropertyInfos for Index parameters.


PropertyInfo pi = member as PropertyInfo; 

if (pi != null)

{ 

if (pi.GetIndexParameters().Length > 0 ) 

throw new ArgumentException("May not contain indexer properties.", "members");

}

Even though the fix was pretty easy once the cause was identified, bugs in MSIL injection are very hard to track down. The exception could point to any other part of the injected code being incorrect. I haven’t seen any effective way (or tool for that matter) to debug or review runtime injected code yet. It appears, one is pretty much left with nothing but trial and error in such cases.

Categories: Open Source, Projects
  1. No comments yet.
  1. No trackbacks yet.

Leave a comment