Common Language Runtime detected an invalid program

Mar 25, 2008 at 1:28 PM
Edited Mar 25, 2008 at 1:30 PM
Ok, this is weird. I got the exception above for a very simple expression:

  True OR (x() > 1)

The ResolveFunction for x returns typeof(int), and the InvokeFunction is not even called.

I have simplified the code as much as possible, so this is my little buggy example:

        private void button1_Click (object sender, EventArgs e)
        {
            string text = @"True OR (x(3) > 1)";
            ExpressionContext ctx = new ExpressionContext ();
            ctx.Variables.ResolveFunction += new EventHandler<ResolveFunctionEventArgs> (Functions_ResolveFunction);
            ctx.Variables.InvokeFunction += new EventHandler<InvokeFunctionEventArgs> (Functions_InvokeFunction);
            IGenericExpression<bool> executer = ExpressionFactory.CreateGeneric<bool> (text, ctx);
            bool result = executer.Evaluate ();
        }
 
        void Functions_InvokeFunction (object sender, InvokeFunctionEventArgs e)
        {
            e.Result = 3;
        }
 
        void Functions_ResolveFunction (object sender, ResolveFunctionEventArgs e)
        {
            e.ReturnType = typeof (int);
        }

Maybe I am too tired today, but... is there anything that I am missing here?
Coordinator
Mar 27, 2008 at 12:58 AM
That exception means I'm emitting invalid IL. In other words it's a bug I need to look into.
Mar 28, 2008 at 8:18 AM
After digging through the code - and please forgive me if I am saying nonsenses -, I think the problem is the IL Generator is missing the local variables when created inside the DoEmitLogical() call. Why? I don't know.

This is the emitted IL for "true or (x(3)>3)":

.method public static object Evaluate(object, class [Ciloci.Flee]Ciloci.Flee.ExpressionContext, class [Ciloci.Flee]Ciloci.Flee.VariableCollection) cil managed
{
    .maxstack 6
    L_0000: ldc.i4.1 
    L_0001: brtrue.s L_0024
    L_0003: ldarg.2 
    L_0004: ldstr "x"
    L_0009: ldc.i4.1 
    L_000a: newarr object
    L_000f: stloc.0 
    L_0010: ldloc.0 
    L_0011: ldc.i4.0 
    L_0012: ldc.i4.3 
    L_0013: box int32
    L_0018: stelem.ref 
    L_0019: ldloc.0 
    L_001a: callvirt instance !!0 [Ciloci.Flee]Ciloci.Flee.VariableCollection::GetFunctionResultInternal<int32>(string, object[])
    L_001f: ldc.i4.3 
    L_0020: cgt 
    L_0022: br.s L_0025
    L_0024: ldc.i4.1 
    L_0025: box bool
    L_002a: ret 
}

And PEVerify.exe says

[IL]: Error: [Expression.dll : <Module>::Evaluate][offset 0x0000000F] Unrecognized local variable number.
1 Error Verifying Expression.dll

which is right, because it is trying to store things in the locals, but there are no locals. It is missing the initial declaration

   .locals init (
        [0] object[] objArray)

My knowledge of IL is just that. I cannot fix the sourcecode... Does this helps?

As a workaround, I have changed the sourcecode to use bitwise operation for these cases too... it is non-optimal, and it does not short-circuit anymore, but the IL code seems to work.

Public Overrides Sub Emit(ByVal ilg As FleeILGenerator, ByVal services As IServiceProvider)
    Dim resultType As Type = Me.ResultType
 
    'If resultType Is GetType(Boolean) Then
    '    Me.DoEmitLogical(ilg, services)
    'Else
        MyLeftChild.Emit(ilg, services)
        ImplicitConverter.EmitImplicitConvert(MyLeftChild.ResultType, resultType, ilg)
        MyRightChild.Emit(ilg, services)
        ImplicitConverter.EmitImplicitConvert(MyRightChild.ResultType, resultType, ilg)
        Me.EmitBitwiseOperation(ilg, MyOperation)
    'End If
End Sub

The new IL now has the .locals section in place, and it PEVerifies.

.method public static object Evaluate(object, class [Ciloci.Flee]Ciloci.Flee.ExpressionContext, class [Ciloci.Flee]Ciloci.Flee.VariableCollection) cil managed
{
    .maxstack 6
    .locals init (
        [0] object[] objArray)
    L_0000: ldc.i4.1 
    L_0001: ldarg.2 
    L_0002: ldstr "x"
    L_0007: ldc.i4.1 
    L_0008: newarr object
    L_000d: stloc.0 
    L_000e: ldloc.0 
    L_000f: ldc.i4.0 
    L_0010: ldc.i4.3 
    L_0011: box int32
    L_0016: stelem.ref 
    L_0017: ldloc.0 
    L_0018: callvirt instance !!0 [Ciloci.Flee]Ciloci.Flee.VariableCollection::GetFunctionResultInternal<int32>(string, object[])
    L_001d: ldc.i4.3 
    L_001e: cgt 
    L_0020: or 
    L_0021: box bool
    L_0026: ret 
}
Coordinator
Mar 28, 2008 at 3:03 PM
You're right, the missing locals declaration was causing the exception.

I checked in the fix for this bug so you can do a build from source if you need it fixed before the next release.
Coordinator
Mar 29, 2008 at 2:15 AM
Fixed in Flee-0.9.17.5