Capgemini / Cauldron

C# Toolkit
MIT License
76 stars 18 forks source link

IConstructorInterceptor causes assembly to fail verification (and won't run) #70

Closed 0x15e closed 5 years ago

0x15e commented 5 years ago

Using package versions:

Attempting to build a .NET Framework console app for framework 4.7.2. There's nothing in the project but the necessary nuget packages for the interceptors, an attribute class, a class where it's applied, and Program.cs.

peverify /verbose produces the error:

Microsoft (R) .NET Framework PE Verifier.  Version  4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.

[IL]: Error: [C:\Users\0x15e\source\repos\CauldronExeFailReproduction\CauldronExeFailReproduction\bin\Debug\CauldronExeFailReproduction.exe : CauldronExeFailReproduction.TestSubject::.ctor][mdToken=0x6000008][offset 0x0000006C][found ref 'Cauldron.Interception.IConstructorInterceptor'][expected ref 'System.Exception'] Unexpected type on the stack.
[IL]: Error: [C:\Users\0x15e\source\repos\CauldronExeFailReproduction\CauldronExeFailReproduction\bin\Debug\CauldronExeFailReproduction.exe : CauldronExeFailReproduction.TestSubject::.ctor][mdToken=0x6000008][offset 0x0000006C] Stack underflow.
2 Error(s) Verifying CauldronExeFailReproduction.exe

Attempting to run it anyway results in a System.InvalidProgramException: "Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program."

Here's the IL of the class where the interceptor is applied:

.class public auto ansi beforefieldinit CauldronExeFailReproduction.TestSubject
    extends [mscorlib]System.Object
{
    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor (
            string someParam
        ) cil managed 
    {
        // Method begins at RVA 0x20d4
        // Code size 115 (0x73)
        .maxstack 5
        .locals init (
            [0] object[],
            [1] class [Cauldron.Interception]Cauldron.Interception.IConstructorInterceptor,
            [2] class [mscorlib]System.Exception
        )

        // (no C# code)
        IL_0000: ldc.i4.1
        IL_0001: newarr [mscorlib]System.Object
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: ldc.i4.0
        //  object[] values = new object[1]
        //  {
        //      someParam
        //  };
        IL_0009: ldarg.1
        // (no C# code)
        IL_000a: stelem.ref
        // IConstructorInterceptor constructorInterceptor = new TestConstructorFailureAttribute();
        IL_000b: newobj instance void CauldronExeFailReproduction.TestConstructorFailureAttribute::.ctor()
        IL_0010: stloc.1
        // constructorInterceptor.OnBeforeInitialization(typeof(TestSubject), MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(TestSubject).TypeHandle), values);
        IL_0011: ldloc.1
        IL_0012: ldtoken CauldronExeFailReproduction.TestSubject
        IL_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        IL_001c: ldtoken method instance void CauldronExeFailReproduction.TestSubject::.ctor(string)
        IL_0021: ldtoken CauldronExeFailReproduction.TestSubject
        IL_0026: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
        IL_002b: ldloc.0
        IL_002c: callvirt instance void [Cauldron.Interception]Cauldron.Interception.IConstructorInterceptor::OnBeforeInitialization(class [mscorlib]System.Type, class [mscorlib]System.Reflection.MethodBase, object[])
        // base..ctor();
        IL_0031: ldarg.0
        IL_0032: call instance void [mscorlib]System.Object::.ctor()
        .try
        {
            .try
            {
                // constructorInterceptor.OnEnter(typeof(TestSubject), this, MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(TestSubject).TypeHandle), values);
                IL_0037: ldloc.1
                IL_0038: ldtoken CauldronExeFailReproduction.TestSubject
                IL_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
                IL_0042: ldarg.0
                IL_0043: ldtoken method instance void CauldronExeFailReproduction.TestSubject::.ctor(string)
                IL_0048: ldtoken CauldronExeFailReproduction.TestSubject
                IL_004d: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
                IL_0052: ldloc.0
                IL_0053: callvirt instance void [Cauldron.Interception]Cauldron.Interception.IConstructorInterceptor::OnEnter(class [mscorlib]System.Type, object, class [mscorlib]System.Reflection.MethodBase, object[])
                // (no C# code)
                IL_0058: leave.s IL_0072
            } // end .try
            catch [mscorlib]System.Exception
            {
                IL_005a: stloc.2
                // if (constructorInterceptor.OnException(e))
                IL_005b: ldloc.1
                IL_005c: ldloc.2
                IL_005d: callvirt instance bool [Cauldron.Interception]Cauldron.Interception.IConstructorInterceptor::OnException(class [mscorlib]System.Exception)
                // (no C# code)
                IL_0062: ldc.i4.1
                IL_0063: ceq
                IL_0065: brfalse.s IL_0069

                IL_0067: rethrow

                IL_0069: leave.s IL_0072
            } // end handler
        } // end .try
        finally
        {
            // ((IConstructorInterceptor)/*Error near IL_006c: Stack underflow*/).OnException((Exception)constructorInterceptor);
            IL_006b: ldloc.1
            IL_006c: callvirt instance bool [Cauldron.Interception]Cauldron.Interception.IConstructorInterceptor::OnException(class [mscorlib]System.Exception)
            // (no C# code)
            IL_0071: endfinally
        } // end handler

        IL_0072: ret
    } // end of method TestSubject::.ctor

} // end of class CauldronExeFailReproduction.TestSubject
reflection-emit commented 5 years ago

Does it have the same error in Release mode with optimization turned on?

0x15e commented 5 years ago

I just checked and confirmed the same thing happens in Release with optimizations on (also regardless of platform target and bitness preference).

0x15e commented 5 years ago

In case it helps anything, here are my msbuild and csc versions:

reflection-emit commented 5 years ago

OK thanks… I'll look into this as soon as possible.

reflection-emit commented 5 years ago

Fixed … Next version will have the fix...

0x15e commented 5 years ago

Fantastic. I just built from source and confirmed everything's working on my end as well. Thanks!

reflection-emit commented 5 years ago

Nuget packages are coming. I am unlisting older and merged packages.