This project is read-only.

Generated code only executes after additional compilation with ilasm

Topics: PE Writer
Aug 6, 2011 at 4:34 PM

Didn't want to continue the last discussion because it went to much off topic. So here is the problem I am running into:

I have a compiled Assembly, which is a Unit Test that is meant to be executed with Chess. The assembly runs and everything is fine. I open the assembly with CCI and try to build a lock block around one of the statements and therefore trying to call Monitor.Enter and Exit (tried both the 3.5 and the 4.0 implementation of the lock(){}). I use as basis the ILMutator Sample.

So, I open, update and save the assembly. After that the Assembly throws the following Runtime Exception:

Unhanded Exception: System.TypeLoadException: Could not load type 'System.Threading.Monitor' from assembly mscorlib.

What is more interesting is that I opened the assembly with ildasm and dumped the il code. Then I compiled it with ilasm and the code executes just fine. I dumped the il once again and compared both. The only thing different in the Assemblies is nothing I have or can edit with CCI (At least as far as I am aware of). Most diffrenses are comments, sizes, etc...

I have dumped the code of the three assemblies, original, working and nonworking and included also the assemblies themeselves.

I used the latest (CCI AST) SVN revision 64479.

Has anyone any idea, what is going on. Is there some sort of a bug in CCI or am I doing something wrong.

You can download the files from: http://www.atanasdimitrov.com/Downloads/CCIExaple.zip

Thanks a lot in advance.

Aug 8, 2011 at 9:56 PM

I've had a look at your binaries and it appears that the bad assembly has a type reference table that has suspicious entries. When you dump to IL and then assemble the IL, the type reference table gets fixed up and hence things work again.

You could try to run MetadataValidator on your object model before writing it out.

If you're still stuck, please see if you can construct a small program that exhibits this behavior. I might be able to tell you more if I can look at it in the debugger.

Aug 8, 2011 at 10:10 PM

Thanks for your reply, after several days of research on this I decided to go another way and looked through all the samples again. I replaced my existing construction of the MethodReferences with the one that uses the UnitHelper and the TypeHelper and it worked. The only problem with this is that I wasn't able to reference Monitor.Enter(object, ref bool). I just didn't find a way to describe the referenced argument and I keep getting the Dummy Implementation. But this is not that bad

var nameTable = host.NameTable;            
            var platformType = host.PlatformType;
            var systemObject = platformType.SystemObject;
            var systemBoolean = platformType.SystemBoolean;
 
            var coreAssembly = host.LoadAssembly(host.CoreAssemblySymbolicIdentity);
            var systemThreadingMonitor = UnitHelper.FindType(nameTable, coreAssembly, "System.Threading.Monitor");
            this.m_monitorEnter = TypeHelper.GetMethod(systemThreadingMonitor, nameTable.GetNameFor("Enter"), systemObject);
            this.m_monitorExit = TypeHelper.GetMethod(systemThreadingMonitor, nameTable.GetNameFor("Exit"), systemObject);

The old code was based on the IlMutator code and how the MethodCalls were constructed there. Here is part of the code, in case this helps. I don't have the original code any more.

var SystemThreadingMonitorType =
              new Microsoft.Cci.Immutable.NamespaceTypeReference(
                host, systemObject.ContainingUnitNamespace,
                nameTable.GetNameFor("Threading.Monitor"),
                0, falsefalsePrimitiveTypeCode.NotPrimitive);
 
            List<IParameterTypeInformation> pti = new List<IParameterTypeInformation>();
            pti.Add(new ParameterTypeInformation() { IsByReference = false, Type = systemObject, Index = 0 });
            pti.Add(new ParameterTypeInformation() { IsByReference = true, Type = systemBoolean, Index = 1 });
 
            this.m_monitorEnter = new Microsoft.Cci.MethodReference(
              this.host, SystemThreadingMonitorType,
              CallingConvention.Default,
              systemVoid,
              nameTable.GetNameFor("Enter"),
              0, pti);
Calling the other two methods (Enter(onject), Exit(object)) was done the exact same way and it didn't matter which one was used or where, the error message would always appear.

Could this be some sort of bug somewhere?
Aug 9, 2011 at 1:05 AM

There may well be a some sort of bug somewhere. :-)

But it will really help to have a clear way of reproducing the bug.

Aug 10, 2011 at 10:10 AM

I will try to re-implement the code and send it to you so that you can analyze it. I only hope I have enough time to do it.