Bug 52600

Summary: Full AOT: Strange combination of structs, generics, and enums causes runtime failure
Product: [Mono] Runtime Reporter: Antony Male <antony.male>
Component: JITAssignee: Zoltan Varga <vargaz>
Severity: normal CC: mono-bugs+mono, mono-bugs+runtime, vargaz
Priority: ---    
Version: 4.6.0 (C8)   
Target Milestone: ---   
Hardware: All   
OS: All   
Tags: Is this bug a regression?: ---
Last known good build:
Attachments: File which reproduces the issue

Description Antony Male 2017-02-17 11:39:08 UTC
Created attachment 19863 [details]
File which reproduces the issue

This issue was first reported to me under Xamarin.iOS (on the real device only, the simulator is fine). I managed to reproduce and reduce under Mono on Linux, which is why I filed under "Compilers" and "All Hardware / All OS". Please refile if this was a bad assumption.

Please see the attached sample. I've commented the bits that seem to be critical: it seems to be that the AOT can't figure out that a generic method is called with a struct generic type parameter, but only if that generic method references an enum member on the struct.

Steps to reproduce:

    mcs Program.cs
    mono --aot=full Program.exe
    mono --full-aot Program.exe

On my machine, the output is:

    * Assertion at mini-generic-sharing.c:2351, condition `info' not met


      at <unknown> <0xffffffff>
      at Test.TestClass`1<T_INT>.Part1 () <0x00029>
      at Test.Program.Main (string[]) <0x0001f>
      at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0x000cc>

    Native stacktrace:

            mono() [0x4b18ff]
            /usr/lib/libpthread.so.0(+0x11080) [0x7f2dc44a3080]
            /usr/lib/libc.so.6(gsignal+0xcf) [0x7f2dc3f1004f]
            /usr/lib/libc.so.6(abort+0x16a) [0x7f2dc3f1147a]
            mono() [0x6666c9]
            mono() [0x66695c]
            mono() [0x666af3]
            mono() [0x4be8ef]
            mono() [0x4b2716]
            /home/antony/test/StateMechanic/src/Test/bin/Debug/mscorlib.dll.so(generic_trampoline_rgctx_lazy_fetch+0x17f) [0x7f2dc178cc6f]

    Debug info from gdb:

    Got a SIGABRT while executing native code. This usually indicates
    a fatal error in the mono runtime or one of the native libraries
    used by your application.

    Aborted (core dumped)

(Disclaimer: when I first tried to reproduce it on my machine, it failed with "Failed to load AOT module '/usr/lib/mono/4.5/mscorlib.dll.so' while running in aot-only mode: not compiled with --aot=full". I manually copied dlls out of /usr/lib/mono/4.5 into my CWD, AOT'd them with --aot=full, and set MONO_PATH to the CWD. I don't believe this has affected the outcome in any way).

For completion, the original (non-reduced) problem produced the following output on Xamarin.iOS (probably incomplete - it was reported by a third party):

    **System.ExecutionEngineException** has been thrown
    Attempting to JiT compile method 'StateMechanic.StateMachine`1<StateMechanic.State>:RequestEver(StateMechanic.EventTransitionInvoker`1<StateMechanic.State>)' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information

    at StateMechanic.StateMachine`1[TState].StateMechanic.IEventDelegate.RequestEventFireFromEvent (StateMechanic.Event event, EventFireMethod eventFireMethod) [0x0000a] in <filename unknown>:0 
      at StateMechanic.Event.RequestEventFireFromEvent (EventFireMethod eventFireMethod) [0x0000f] in <filename unknown>:0 
      at StateMechanic.Event.Fire () [0x00000] in <filename unknown>:0
Comment 1 Zoltan Varga 2017-02-18 21:44:03 UTC
Fixed in mono master 15a6c8a875281b04b4bcd69c7b330faf0f4a7ace. Thanks for the testcase.
Comment 2 Antony Male 2017-02-18 23:17:51 UTC
Awesome, nice one. Thanks!
Comment 3 Antony Male 2017-02-18 23:31:16 UTC
Is there a sensible workaround, until that fix makes its way into Xamarin.iOS?
Comment 4 Zoltan Varga 2017-02-19 05:22:03 UTC
The workaround is to avoid calls which are made on 'constrained' types, and return enums, like in the testcase:

       public void Part2<TFoo>(TFoo foo) where TFoo : IFoo // <-- Needs to be generic
            Console.WriteLine(foo.Bar); // <-- Needs to reference the enum member from foo
                                        // (if I add an int member and reference that, everything is OK)

Here TFoo can be either a reference or a struct type, since both can implement IFoo, so its a complicated case.
Comment 5 Antony Male 2017-02-19 13:03:33 UTC
OK, so it's the combination of a constrained type and anything which returns an enum which causes the issue. I see, thanks!