Skip to content

NativeAOT RC2 crash with GVMs on linux-x64  #77070

Closed

Description

@agocke

Output:

Process terminated. Generic virtual method pointer lookup failure.

Declaring type handle: MethodTable:0x00005608B8D60CF8
Target type handle: MethodTable:0x00005608B8DCE250
Method name: VisitDictionary
Instantiation:
Argument 00000000: MethodTable:0x00005608B8D79B30

backtrace

* thread #1, name = 'dnvm', stop reason = signal SIGABRT
  * frame #0: 0x00007fde39ce1a7c libc.so.6`pthread_kill + 300
    frame #1: 0x00007fde39c8d476 libc.so.6`raise + 22
    frame #2: 0x00007fde39c737f3 libc.so.6`abort + 211
    frame #3: 0x00005608b845b609 dnvm`SystemNative_Abort at pal_threading.c:286:5
    frame #4: 0x00005608b85f8044 dnvm`S_P_CoreLib_System_RuntimeExceptionHelpers__FailFast_1 at RuntimeExceptionHelpers.cs:281
    frame #5: 0x00005608b878fc2e dnvm`S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeLoaderEnvironment__ResolveGenericVirtualMethodTarget_Static at TypeLoaderEnvironment.GVMResolution.cs:628
    frame #6: 0x00005608b878e82f dnvm`S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeLoaderEnvironment__TryGetGenericVirtualTargetForTypeAndSlot at TypeLoaderEnvironment.GVMResolution.cs:100
    frame #7: 0x00005608b86c4aa5 dnvm`S_P_CoreLib_Internal_Runtime_CompilerServices_GenericVirtualMethodSupport__GVMLookupForSlotWorker at GenericVirtualMethodSupport.cs:31
    frame #8: 0x00005608b86c4b5e dnvm`S_P_CoreLib_Internal_Runtime_CompilerServices_GenericVirtualMethodSupport__GVMLookupForSlotWorker at GenericVirtualMethodSupport.cs:47
    frame #9: 0x00005608b86c4d52 dnvm`S_P_CoreLib_Internal_Runtime_CompilerServices_GenericVirtualMethodSupport__GVMLookupForSlot at GenericVirtualMethodSupport.cs:89
    frame #10: 0x00005608b86e36a0 dnvm`S_P_CoreLib_System_Runtime_TypeLoaderExports___c___GVMLookupForSlot_b__14_0 at TypeLoaderExports.cs:144
    frame #11: 0x00005608b8699e65 dnvm`S_P_CoreLib_System_Runtime_TypeLoaderExports__CacheMiss_0 at TypeLoaderExports.cs:218
    frame #12: 0x00005608b8699d85 dnvm`S_P_CoreLib_System_Runtime_TypeLoaderExports__GVMLookupForSlot at TypeLoaderExports.cs:142
    frame #13: 0x00005608b88ac7c5 dnvm`Serde_Serde_Json_JsonDeserializer__DeserializeDictionary<System___Canon__System___Canon> at JsonDeserializer.cs:94
    frame #14: 0x00005608b887a06f dnvm`dnvm_Dnvm_Update_Release_SerdeVisitor__Serde_IDeserializeVisitor_Dnvm_Update_Release__VisitDictionary<Serde_Serde_Json_JsonDeserializer_DeDictionary> at Dnvm.Update.Release.IDeserialize.cs:33

Figuring out how to upload the exe and core dump

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Oct 15, 2022
  2. added and removed
    untriagedNew issue has not been triaged by the area owner
    on Oct 15, 2022
  3. added this to the 7.0.x milestone on Oct 15, 2022
  4. agocke commented on Oct 15, 2022

    @agocke
    MemberAuthor
  5. agocke commented on Oct 20, 2022

    @agocke
    MemberAuthor

    I've got a minimal repro and some more info about this:

    using System.Collections.Generic;
    
    // Regression test for https://github.com/dotnet/runtime/issues/77070
    public static class Gvm77070
    {
        public static int Run()
        {
            var deserializer = new JsonDeserializer();
            var visitor = new Release.SerdeVisitor();
            deserializer.DeserializeDictionary<Release, Release.SerdeVisitor>(visitor);
            return 100;
        }
    
        public partial record struct Release
        {
            public sealed class SerdeVisitor : IDeserializeVisitor<Release>
            {
                void IDeserializeVisitor<Release>.VisitDictionary<D>(ref D d)
                {
                    d.GetNextValue<DictWrap<string, StringWrap, string>>();
                }
            }
        }
    
        public record StringWrap(string Value)
            : IDeserialize
        {
            public static void Deserialize<D>(ref D deserializer)
                where D : IDeserializer
            {
            }
        }
    
        public readonly struct DictWrap<TKey, TKeyWrap, TValue> : IDeserialize
            where TKey : notnull
            where TKeyWrap : IDeserialize
        {
            static void IDeserialize.Deserialize<D>(ref D deserializer)
            {
                deserializer.DeserializeDictionary<Dictionary<TKey, TValue>, Visitor>(new Visitor());
            }
            private sealed class Visitor : IDeserializeVisitor<Dictionary<TKey, TValue>>
            {
                void IDeserializeVisitor<Dictionary<TKey, TValue>>.VisitDictionary<D>(ref D d)
                {
                    d.GetNextValue<TKeyWrap>();
                }
            }
        }
    
        public interface IDeserializeVisitor<T>
        {
            void VisitDictionary<D>(ref D d) where D : IDeserializeDictionary;
        }
    
        public interface IDeserialize
        {
            static abstract void Deserialize<D>(ref D deserializer) where D : IDeserializer;
        }
    
        public interface IDeserializeDictionary
        {
            void GetNextValue<D>() where D : IDeserialize;
        }
    
        public interface IDeserializer
        {
            void DeserializeDictionary<T, V>(V v) where V : class, IDeserializeVisitor<T>;
        }
        public sealed partial class JsonDeserializer : IDeserializer
        {
            public void DeserializeDictionary<T, V>(V v) where V : class, IDeserializeVisitor<T>
            {
                var map = new DeDictionary(this);
                v.VisitDictionary(ref map);
            }
    
            private struct DeDictionary : IDeserializeDictionary
            {
                private JsonDeserializer _deserializer;
                public DeDictionary(JsonDeserializer de)
                {
                    _deserializer = de;
                }
    
                public void GetNextValue<D>() where D : IDeserialize
                {
                    D.Deserialize(ref _deserializer);
                }
            }
        }
    }

    The problem appears to be something about static interface methods with generics. It looks like this is blowing up in the type loader, which doesn't know how to work with this method specification. I'm not sure what the fix is, but I'm still looking into it.

  6. MichalStrehovsky commented on Oct 27, 2022

    @MichalStrehovsky
    Member

    Workaround is the following RD.XML (I constructed thing by looking up the symbols associated with the addresses in the FailFast) - it pregenerates the method dictionary we're failing to build at runtime:

    <Directives>
      <Application>
        <Assembly Name="repro">
          <Type Name="Gvm77070+DictWrap`3+Visitor[[System.String, mscorlib],[Gvm77070+StringWrap],[System.String,mscorlib]]">
            <Method Name="Gvm77070.IDeserializeVisitor&lt;System.Collections.Generic.Dictionary&lt;TKey,TValue>>.VisitDictionary" Dynamic="Required All">
              <GenericArgument Name="Gvm77070+JsonDeserializer+DeDictionary" />
            </Method>
          </Type>
        </Assembly>
      </Application>
    </Directives>
    
    

    I looked at this in a debugger myself and yep, this needs to be fixed in the type loader (we need to implement the missing dictionary kind that this is throwing about) and it is a hard fix:

     	reproNative.exe!S_P_CoreLib_System_Runtime_EH__RhThrowEx() Line 556	Unknown
     	[External Code]	
    >	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_GenericDictionaryCell__ParseAndCreateCell() Line 1879	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_GenericDictionaryCell__BuildDictionary() Line 1071	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeBuilder__ParseNativeLayoutInfo() Line 486	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeBuilder__PrepareMethod() Line 223	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_GenericDictionaryCell_MethodCell__Prepare() Line 659	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_GenericDictionaryCell__BuildDictionary() Line 1075	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeBuilder__ParseNativeLayoutInfo() Line 486	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeBuilder__PrepareMethod() Line 223	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeBuilder__BuildMethod() Line 1654	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeBuilder__TryBuildGenericMethod_0() Line 2071	Unknown
     	reproNative.exe!S_P_TypeLoader_Internal_Runtime_TypeLoader_TypeLoaderEnvironment__TryGetGenericVirtualMethodPointer() Line 382	Unknown
    

    We need to call into GVM resolution logic as part of type loading and build whatever GVM resolution logic came up with. Either that or generate something that will allow us to lazily resolve this once it's needed.

    Touching anything in the type loader is pretty high risk. To set expectations, the fix might be too risky for servicing.

  7. modified the milestones: 7.0.x, 8.0.0 on Nov 18, 2022
  8. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 13, 2023
  9. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 16, 2023
  10. ghost locked as resolved and limited conversation to collaborators on Feb 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions