none
Stack depth differs depending on path. RRS feed

  • Question

  • Hello everyone. I am developing a compiler using Reflection.Emit and I have ran into a error than I cannot seem to figure out.

     

    My compiler is pumping out the following IL:

    .class private auto ansi App
    	extends [mscorlib]System.Object
    {
    	// Methods
    	.method public static 
    		void Main () cil managed 
    	{
    		// Method begins at RVA 0x2050
    		// Code size 127 (0x7f)
    		.maxstack 5
    		.entrypoint
    		.locals init (
    			[0] int32,
    			[1] int32,
    			[2] string,
    			[3] string,
    			[4] string
    		)
    
    		.try
    		{
    			IL_0000: ldc.i4 2
    			IL_0005: stloc.0
    			IL_0006: ldc.i4 1
    			IL_000b: stloc.1
    			// loop start (head: IL_000c)
    				IL_000c: ldstr "var a={0}"
    				IL_0011: ldloc.0
    				IL_0012: box [mscorlib]System.Int32
    				IL_0017: castclass [mscorlib]System.Object
    				IL_001c: call string [mscorlib]System.String::Format(string, object)
    				IL_0021: stloc.2
    				IL_0022: ldstr "var b={0}"
    				IL_0027: ldloc.1
    				IL_0028: box [mscorlib]System.Int32
    				IL_002d: castclass [mscorlib]System.Object
    				IL_0032: call string [mscorlib]System.String::Format(string, object)
    				IL_0037: stloc.3
    				IL_0038: ldloc.2
    				IL_0039: ldloc.3
    				IL_003a: ldstr "a+b"
    				IL_003f: ldstr ";"
    				IL_0044: call string [mscorlib]System.String::Concat(string, string)
    				IL_0049: call string [Mizu.Lib.Evaluator]Mizu.Lib.Evaluator.Evaluator::Eval(string)
    				IL_004e: stloc.s 4
    				IL_0050: ldloc.s 4
    				IL_0052: call void [mscorlib]System.Console::WriteLine(string)
    				IL_0057: ldloc 1
    				IL_005b: nop
    				IL_005c: nop
    				IL_005d: ldc.i4.1
    				IL_005e: add
    				IL_005f: stloc.1
    				IL_0060: ldloc 1
    				IL_0064: nop
    				IL_0065: nop
    				IL_0066: ldc.i4 10
    				IL_006b: clt
    				IL_006d: brtrue IL_000c
    			// end loop
    			IL_0072: leave IL_007e
    		} // end .try
    		catch [mscorlib]System.Exception
    		{
    			IL_0077: rethrow
    
    			IL_0079: leave IL_007e
    		} // end handler
    
    		IL_007e: ret
    	} // end of method App::Main
    
    	.method public specialname rtspecialname 
    		instance void .ctor () cil managed 
    	{
    		// Method begins at RVA 0x20ec
    		// Code size 7 (0x7)
    		.maxstack 2
    
    		IL_0000: ldarg.0
    		IL_0001: call instance void [mscorlib]System.Object::.ctor()
    		IL_0006: ret
    	} // end of method App::.ctor
    
    } // end of class App
    

    The error is on the "IL_006d: brtrue IL_000c" line. I understand that the VB/C# equivalent would be:

    Public Shared Sub Main()
      Try
        Dim x As Integer = 2
        Dim i As Integer = 1
        While i < 10
          Dim a As String = "var a={0}"
          Dim a2 As String = String.Format(a,x.ToString())
          '... same with b
          Dim result As String = Eval(String.Concat(a2,b2,"a+b",";"))
          i += 1
        End While
      Catch ex As Exception
      End Try
    End Sub
    


    Lastly, here is the complete output from Perverify:

    Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.1
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    [IL]: Error: [C:\Users\alex\Documents\Visual Studio 2010\Projects\Mizu\Mizu\bin\
    Debug\ExampleOutput.exe : App::Main][mdToken=0x6000001][offset 0x0000006D] Stack
     depth differs depending on path.
    1 Error(s) Verifying C:\Users\alex\Documents\Visual Studio 2010\Projects\Mizu\Mi
    zu\bin\Debug\ExampleOutput.exe

    Thanks in advance.


    Current Project: Notepad.NET http://notepadnet.codeplex.com
    Wednesday, August 17, 2011 5:56 PM

Answers

  • OK, so use the params overload. Here's a sample that uses this overload to concatenate 2 strings passed as arguments (only 2 to keep the example short, you can have as many as you want):

    DynamicMethod m = new DynamicMethod("foo", typeof(string), new[] { typeof(string), typeof(string) });
    ILGenerator il = m.GetILGenerator();
    
    il.Emit(OpCodes.Ldc_I4, 2);
    il.Emit(OpCodes.Newarr, typeof(string));
    
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Stelem_Ref);
    
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stelem_Ref);
    
    il.EmitCall(OpCodes.Call, typeof(string).GetMethod("Concat", new[] { typeof(string[]) }, null), null);
    il.Emit(OpCodes.Ret);
    
    Func<string, string, string> d = (Func<string, string, string>)m.CreateDelegate(typeof(Func<string, string, string>));
    Console.WriteLine(d("abc", "def"));
    
    

    • Marked as answer by NeonInari Wednesday, August 17, 2011 9:19 PM
    Wednesday, August 17, 2011 8:26 PM
    Moderator

All replies

  • It looks like you're calling the Concat overload that takes only 2 arguments but push 4 on the stack:

    IL_0038: ldloc.2
    IL_0039: ldloc.3
    IL_003a: ldstr "a+b"
    IL_003f: ldstr ";"
    IL_0044: call string [mscorlib]System.String::Concat(string, string)
    

    Wednesday, August 17, 2011 7:10 PM
    Moderator
  • It looks like you're calling the Concat overload that takes only 2 arguments but push 4 on the stack:

     

    IL_0038: ldloc.2
    IL_0039: ldloc.3
    IL_003a: ldstr "a+b"
    IL_003f: ldstr ";"
    IL_0044: call string [mscorlib]System.String::Concat(string, string)
    

     

    Yeah, I had trouble with that. I can't call the (params string[]) version from the ILGenerator.

     

    EDIT: Yeah, I cannot find a way to get the MethodInfo that is specific to the params version of Concat. Is there something I missing?


    Current Project: Notepad.NET http://notepadnet.codeplex.com
    • Edited by NeonInari Wednesday, August 17, 2011 7:51 PM Added more info.
    Wednesday, August 17, 2011 7:37 PM
  • But there is an overload that takes 4 string parameters, you don't need the params overload.

    http://msdn.microsoft.com/en-us/library/0eafbze3

    Wednesday, August 17, 2011 7:52 PM
    Moderator
  • Actually, I do because at runtime, I will not know the exact amount of strings its going to load. I do not want to have to hard code the amount into the compiler.

     

     


    Current Project: Notepad.NET http://notepadnet.codeplex.com
    Wednesday, August 17, 2011 8:03 PM
  • OK, so use the params overload. Here's a sample that uses this overload to concatenate 2 strings passed as arguments (only 2 to keep the example short, you can have as many as you want):

    DynamicMethod m = new DynamicMethod("foo", typeof(string), new[] { typeof(string), typeof(string) });
    ILGenerator il = m.GetILGenerator();
    
    il.Emit(OpCodes.Ldc_I4, 2);
    il.Emit(OpCodes.Newarr, typeof(string));
    
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Stelem_Ref);
    
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stelem_Ref);
    
    il.EmitCall(OpCodes.Call, typeof(string).GetMethod("Concat", new[] { typeof(string[]) }, null), null);
    il.Emit(OpCodes.Ret);
    
    Func<string, string, string> d = (Func<string, string, string>)m.CreateDelegate(typeof(Func<string, string, string>));
    Console.WriteLine(d("abc", "def"));
    
    

    • Marked as answer by NeonInari Wednesday, August 17, 2011 9:19 PM
    Wednesday, August 17, 2011 8:26 PM
    Moderator
  • Okay, I will give this a shot. Thanks.

    I will post back if I have any more issues. 

    EDIT:

    Your help has helped me finish my compiler. Thank you for your help.

    • Edited by NeonInari Wednesday, August 17, 2011 9:16 PM Added Thanks
    Wednesday, August 17, 2011 8:33 PM