Bugzilla – Bug 320779
[GMCS] gmcs generates invalid IL for iterators
Last modified: 2007-09-15 21:24:23 UTC
---- Reported by sanxiyn@gmail.com 2006-04-06 00:08:38 MST ---- SVN revision 59107. Always reproducible. 1. Get IronPython 1.0 Beta 5 2. Create test.py class C(type): pass 3. Run mono IronPythonConsole.exe test.py with provided binary. This causes no problem. 4. Rebuild IronPython. 5. Run mono IronPythonConsole.exe test.py again. This terminates with SIGTRAP. 6. Run 5 inside gdb. Continuing after receiving SIGTRAP receives SIGSEGV. ---- Additional Comments From sanxiyn@gmail.com 2006-04-06 00:10:48 MST ---- Created an attachment (id=169542) gdb transcript ---- Additional Comments From sanxiyn@gmail.com 2006-04-06 00:48:19 MST ---- I copied the binary compiled by Mono to Windows and ran with MS.NET. Interestingly enough, MS.NET refuses to run the binary. F:\Documents and Settings\sanxiyn\Desktop\IronPython-1.0-Beta5>IronPythonConsole .exe -X:ExceptionDetail test.py Operation could destabilize the runtime. at IronPython.Runtime.CustomFieldIdDict.<GetEnumerator>__17.MoveNext() at IronPython.Runtime.UserType.CreateNamespaceDictionary(IDictionary`2 dict) at IronPython.Runtime.UserType..ctor(String moduleName, String name, Tuple ba ses, IDictionary`2 dict) at IronPython.Runtime.Ops.MakeClass(String mod, String name, Tuple bases, IDi ctionary`2 vars) at __main__.Initialize() in F:\Documents and Settings\sanxiyn\Desktop\IronPyt hon-1.0-Beta5\test.py:line 1 at IronPython.Runtime.PythonModule.Initialize() at IronPython.Hosting.PythonEngine.RunFileInNewModule(String fileName, String moduleName, Boolean skipLine, Boolean& exitRaised) at IronPython.Hosting.PythonEngine.RunFileInNewModule(String fileName, ArrayL ist commandLineArgs, Boolean introspection, Boolean skipLine) at IronPythonConsole.PythonCommandLine.RunFile(PythonEngine engine, ArrayList args) SystemError: Operation could destabilize the runtime. F:\Documents and Settings\sanxiyn\Desktop\IronPython-1.0-Beta5> ---- Additional Comments From vargaz@gmail.com 2006-04-07 13:32:46 MST ---- This is because mcs generates invalid IL for the following test case: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< using System; using System.Collections.Generic; public class Tests { Dictionary<object, object> objData; public IEnumerator<KeyValuePair<object, object>> GetEnumerator() { if (objData != null) { foreach(KeyValuePair<object, object> o in objData){ yield return o; } } } public static int Main () { Tests t = new Tests (); foreach (KeyValuePair<object, object> o in t) Console.WriteLine (o); return 0; } } <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Running this with PEVerify prints: ... Tests+<GetEnumeration>__0:MoveNext ()[offset 0x...] Stack depth differs depending on path. ---- Additional Comments From vargaz@gmail.com 2006-04-07 13:35:33 MST ---- This blocks a gmcs compiled IronPython from working under mono. ---- Additional Comments From miguel@ximian.com 2006-04-07 20:32:17 MST ---- I do get the trap if I run this with Mono and IronPython, but not with the sample test case. I was looking at the disassembled IL, and although it produces the incorrect IL I can not find the two "codepaths" that would lead to the problem. Also, the sample program works fine with Mono (even if I populate the objData Dictionary). ---- Additional Comments From miguel@ximian.com 2006-04-07 21:32:37 MST ---- The Illegal IL report from PEverify seems to be wrong, I reduced the generated routine to this: .method public hidebysig newslot virtual final instance bool MoveNext() cil managed { // Code size 193 (0xc1) .maxstack 12 .locals init (int32 V_0, valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<object,object> V_1) IL_0071: IL_0077: ldarg.0 IL_0078: ldflda valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<object,object> Tests/'<GetEnumerator>__0'::'<1:$s_1>' IL_007d: call instance void valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<object,object>::Dispose() IL_008e: ldarg.0 IL_008f: ldfld int32 Tests/'<GetEnumerator>__0'::$PC IL_0094: switch ( IL_0071) IL_00bf: ldc.0 IL_00c0: ret } // end of method '<GetEnumerator>__0'::MoveNext And PEVerify continued to complain about it, somehow it gets confused by the back switch. ---- Additional Comments From miguel@ximian.com 2006-04-07 21:39:17 MST ---- My bat-feeling is that the IL verifier in MS does not like the jump at the start to the switch, and then the switch jumping back. That sounds lame to me. Am not sure if we can change the compiler easily to change the order in which switch is generated, I will look into that. Sadly, the IronPython problem is probably somewhere else. ---- Additional Comments From miguel@ximian.com 2006-04-18 22:38:14 MST ---- I rewrote the code to produce the switch statement on top, and am still having problems with the resulting executable on PEVerify, am investigating. ---- Additional Comments From miguel@ximian.com 2006-04-19 21:33:46 MST ---- Created an attachment (id=169543) Switch inversion for iterators in MoveNext. ---- Additional Comments From miguel@ximian.com 2006-04-19 22:43:28 MST ---- Martin tracked this down, I likely did a clerical error and got confused. The problem was that we were emitting the instance for Dispose twice: IL_0071: ldarg.0 IL_0072: ldfld valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<object,object> Tests/'<GetEnumerator>__0'::'<1:$s_1>' IL_0077: ldarg.0 IL_0078: ldflda valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<object,object> Tests/'<GetEnumerator>__0'::'<1:$s_1>' The problem was in Foreach's EmitFinally code, there was a duplicated call to enumerator.Emit. Imported an attachment (id=169542) Imported an attachment (id=169543) Unknown operating system unknown. Setting to default OS "Other".