[Mono-bugs] [Bug 51499][Blo] New - Problem with tail. instruction prefix (stack counting error)

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Sat, 29 Nov 2003 12:51:22 -0500 (EST)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by kokholm@it-c.dk.

http://bugzilla.ximian.com/show_bug.cgi?id=51499

--- shadow/51499	2003-11-29 12:51:22.000000000 -0500
+++ shadow/51499.tmp.25323	2003-11-29 12:51:22.000000000 -0500
@@ -0,0 +1,202 @@
+Bug#: 51499
+Product: Mono/Runtime
+Version: unspecified
+OS: 
+OS Details: XP Pro
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Blocker
+Component: misc
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: kokholm@it-c.dk               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: Problem with tail. instruction prefix (stack counting error)
+
+Description of Problem:
+ This problem is a showstopper for running Moscow ML .Net
+ (http://www.dina.kvl.dl/~sestoft/mosml.html) on Mono v0.28.
+ Tried on WinXP Pro and Redhat 9.0.
+
+  Under some circumstances, a tail. instruction prefix in
+ a method body may make the JIT compiler emit eroneous code.
+ It seems to be an offset error in the compilation of ldarg.i
+ instructions and usually leads to unverifiable code or casting
+ errors. I have tried to extract a relatively simple example, 
+ but I have only seen the problem with at least three assemblies
+ in play and the assembly with the tail. prefix loaded by 
+ reflection.
+
+ In the following snippet from the example below,
+  
+   ...
+  tail.
+  callvirt   instance class [M]Value [M]MLClosure::Eval1(class [M]Value)
+  ret
+ THEEND:
+  ldarg.1
+  call       class [M]Value [M]Value::printlna(class [M]Value)
+   ... 
+
+ the final call will actually be called with argument0 (this) as 
+ if the previous instruction was ldarg.0. Removing the tail. prefix 
+ removes the problem. The problem also is somwhat dependent on the 
+ precise code preceding the prefix.
+
+Steps to reproduce the problem:
+1. Save the code below into files A.il, M.cs and C.cs as indicated
+2. Compile the files: to A.dll, M.dll and C.exe:
+      ilasm /dll A.il
+      mcs /target:library M.cs     
+      mcs /reference:M.dll C.cs
+3. Run C.exe:
+      mono C.exe
+   This erroneously writes
+      MLClosure(A.CL2)
+   to the terminal. Remove the tail. instruction prefix near the 
+   end of A.il and repeat. Now mono C.exe writes
+      7
+   to the terminal. Either version will write 7 to the terminal 
+   when run using the MS .Net SDK runtime.
+ 
+------------A.il------------------------------------------------------
+.assembly extern mscorlib {}
+.assembly extern M{}
+.assembly A{}
+.module A.dll
+
+.namespace A
+{
+  .class public auto ansi main extends [mscorlib]System.Object
+  {
+    .field public static class [M]Value[] globals
+
+    .method public specialname rtspecialname 
+            instance void  .ctor() cil managed
+    {
+        ldarg.s    0
+        call       instance void [mscorlib]System.Object::.ctor()
+        ret
+    } 
+
+    .method private specialname rtspecialname static 
+            void  .cctor() cil managed
+    {
+        ldc.i4     0x3
+        newarr     [M]Value
+        stsfld     class [M]Value[] A.main::globals
+        ret
+    } 
+
+    .method public static void  module_init() cil managed
+    {
+        ldsfld     class [M]Value[] A.main::globals
+        ldc.i4     0x1
+        newobj     instance void A.CL1::.ctor()
+        stelem.ref
+        ldsfld     class [M]Value[] A.main::globals
+        ldc.i4     0x2
+        newobj     instance void A.CL2::.ctor()
+        stelem.ref
+        ret
+    } 
+
+  }
+
+  .class public auto ansi CL1 extends [M]MLClosure
+  {
+    .method public specialname rtspecialname 
+            instance void  .ctor() cil managed
+    {
+        ldarg.s    0
+        call       instance void [M]MLClosure::.ctor()
+        ret
+    } 
+    .method public virtual instance class [M]Value 
+            Eval1(class [M]Value A_1) cil managed
+    {
+        ldc.i4     0x1
+	newobj     instance void [M]MLInt::.ctor(int32)
+        ret
+    } 
+  } 
+
+  .class public auto ansi CL2 extends [M]MLClosure
+  {
+    .method public specialname rtspecialname 
+            instance void  .ctor() cil managed
+    {
+        ldarg.s    0
+        call       instance void [M]MLClosure::.ctor()
+        ret
+    } 
+    .method public virtual instance class [M]Value 
+            Eval1(class [M]Value A_1) cil managed
+    {
+        ldc.i4     0x0
+        brfalse    THEEND
+        ldsfld     class [M]Value[] A.main::globals
+        ldc.i4     0x1
+        ldelem.ref
+        castclass  [M]MLClosure
+        ldc.i4     0x0
+	newobj     instance void [M]MLInt::.ctor(int32)
+        tail.
+        callvirt   instance class [M]Value [M]MLClosure::Eval1(class [M]
+Value)
+        ret
+	THEEND:
+        ldarg.1                                          
+        call       class [M]Value [M]Value::printlna(class [M]Value)
+        ret
+    } 
+  } 
+}
+-----------------------------------------------------------------------
+----------------M.cs---------------------------------------------------
+public abstract class Value {
+  public static Value printlna(Value v) {
+    System.Console.WriteLine(v.ToString());
+    return new MLInt(0);
+  }
+}
+
+public class MLInt : Value {
+  public int val;
+  public MLInt(int i) {
+    val = i;
+  }
+  public override string ToString() {
+    return val.ToString();
+  }
+}
+
+public abstract class MLClosure : Value {
+  public abstract Value Eval1(Value v);
+  public override string ToString() {
+    return "MLClosure("+GetType()+")";
+  }
+}
+---------------------------------------------------------------
+-----------------C.cs-------------------------------------------
+using System;
+using System.Reflection;
+public class T_smlcall {
+  public static void Main(string[] args) {
+    Assembly assem = Assembly.LoadFrom("A.dll");
+    Type clinf = assem.GetType("A.main");
+    ConstructorInfo constructor = clinf.GetConstructor(new System.Type
+[0]);
+    object main = constructor.Invoke(new System.Object[0]);
+    MethodInfo initMethod = clinf.GetMethod("module_init");
+    initMethod.Invoke(main,new System.Object[] {});
+    Value[] vals = (Value[])(clinf.GetField("globals").GetValue(main));
+    Value fac = vals[2];
+    Value seven = new MLInt(7);
+    Value mlretval = ((MLClosure)fac).Eval1(seven);
+  }
+}
+-------------------------------------------------------------------------