Skip to content

System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests.TestCustomAttributeDecoder is failed if tc is a native image file #23513

Closed

Description

@YongseopKim

(This tc is in System.Reflection.Metadata.Tests which built with /p:Outerloop=True)

It is failed on x64/arm32/armel(I've checked it on only three arches)

System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests.TestCustomAttributeDecoder [FAIL]
      Assert.Empty() Failure
      Stack Trace:
         /home/dragon/dotnet/x64-dotnet/corefx/src/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs(36,0): at System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests.TestCustomAttributeDecoder()

How to make ni for testing this issue

# crossgen /Platform_Assemblies_Paths $overlay ./System.Reflection.Metadata.Tests.dll
~/dotnet/x64-dotnet/tmp/nopatch_latest/overlay/crossgen /Platform_Assemblies_Paths ~/dotnet/x64-dotnet/tmp/nopatch_latest/overlay ./System.Reflection.Metadata.Tests.dll

In fact, there are more failed tcs if they are ni files.

# in AnyOS.AnyCPU.$BuildMode/System.Runtime.Loader.RefEmitLoadContext.Tests /p:Outerloop=True
System.Runtime.Loader.Tests.RefEmitLoadContextTests.LoadRefEmitAssembly 

# in AnyOS.AnyCPU.$BuildMode/System.Runtime.Tests /p:Outerloop=True
System.Reflection.Tests.AssemblyTests.AssemblyLoadFromBytes
System.Reflection.Tests.AssemblyTests.LoadFrom_SameIdentityAsAssemblyWithDifferentPath_ReturnsEqualAssemblies

# in Unix.AnyCPU.Release.$BuildMode/System.Runtime.Extensions.Tests /p:Outerloop=True
System.Tests.AppDomainTests.AssemblyLoad
System.Tests.AppDomainTests.Load
System.Tests.AppDomainTests.GetAssemblies

The above tcs use Reflection methods, so I think this issue may solve them. If the tcs are failed after this issue is solved, they should be submmited as new issues.

Activity

  1. YongseopKim commented on Sep 11, 2017

    @YongseopKim
    ContributorAuthor

    /cc @dotnet/arm32-contrib @hqueue @parjong

  2. YongseopKim commented on Sep 12, 2017

    @YongseopKim
    ContributorAuthor

    This tc TestCustomAttributeDecoder is testing whether decoding custom attributes of a class works correctly. To test it, CustomAttributeDecoderTests has multiple custom attributes. Remeber the order of the custom attributes.

    namespace System.Reflection.Metadata.Decoding.Tests
    {
        public class CustomAttributeDecoderTests
        {
            // ...
    
            // no arguments
            [Test]
    
            // multiple fixed arguments
            [Test("0", 1, 2.0)]
    
            // multiple named arguments
            [Test(StringField = "0", Int32Field = 1, SByteEnumArrayProperty = new[] { SByteEnum.Value })]
    
            // multiple fixed and named arguments
            [Test("0", 1, 2.0, StringField = "0", Int32Field = 1, DoubleField = 2.0)]
    
            // single fixed null argument
            [Test((object)null)]
            [Test((string)null)]
            [Test((Type)null)]
            [Test((int[])null)]
    
            // ...
    
            // null named arguments
            [Test(ObjectField = null)]
            [Test(StringField = null)]
    
            [Test(Int32ArrayProperty = null)]
    
            private sealed class HasAttributes { }

    At runtime, CoreCLR has the custom attributes as metdata in somewhere. I don't know where the place is, but I can see them by below code. (source from here)

    namespace System.Reflection.Metadata.Decoding.Tests
    {
        public class CustomAttributeDecoderTests
        {
            [Fact]
            public void TestCustomAttributeDecoder()
            {
                Type type = typeof(HasAttributes).GetTypeInfo();
                Console.WriteLine("FullName: {0}", type.FullName);
    
                foreach(CustomAttributeData cad in type.CustomAttributes)
                {
                    if (cad == null)
                    {
                        Console.WriteLine("    null object");
                        continue;
                    }
                    Console.WriteLine("    {0}", cad);
                    Console.WriteLine("         Named arguments");
                    foreach(CustomAttributeNamedArgument cana in cad.NamedArguments)
                    {
                        Console.WriteLine("         MemberInfo: {0}", cana.MemberInfo);
                        CustomAttributeTypedArgument cata = cana.TypedValue;
                        if (cata == null)
                            Console.WriteLine("        CustomAttributeTypedArgument: null");
                        else if (cata.Value == null)
                        {
                            Console.WriteLine("        CustomAttributeTypedArgument.Value: null");
                        }
                        else if (cata.Value.GetType() == typeof(ReadOnlyCollection<CustomAttributeTypedArgument>))
                        {
                            Console.WriteLine("         Array of '{0}':", cata.ArgumentType);
    
                            foreach (CustomAttributeTypedArgument cataElement in 
                                (ReadOnlyCollection<CustomAttributeTypedArgument>) cata.Value)
                            {
                                Console.WriteLine("             Type: '{0}'  Value: '{1}'",
                                    cataElement.ArgumentType, cataElement.Value);
                            }
                        }
                        else
                        {
                            Console.WriteLine("         Type: '{0}'  Value: '{1}'", 
                                cata.ArgumentType, cata.Value);
                        }
                    }
                }

    I found the difference between dll and ni.dll by above code.

    1. .dll prints
    Discovering: System.Reflection.Metadata.Tests
    Discovered:  System.Reflection.Metadata.Tests
    Starting:    System.Reflection.Metadata.Tests
    
    FullName: System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+HasAttributes
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute()]  # HERE
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute("0", (Int32)1, (Double)2)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(StringField = "0", Int32Field = 1, SByteEnumArrayProperty = new System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnu
    m[1] { -1 })]
             Named arguments
             MemberInfo: System.String StringField
             Type: 'System.String'  Value: '0'
             MemberInfo: Int32 Int32Field
             Type: 'System.Int32'  Value: '1'
             MemberInfo: SByteEnum[] SByteEnumArrayProperty
             Array of 'System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnum[]':
                 Type: 'System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnum'  Value: '-1'
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute("0", (Int32)1, (Double)2, StringField = "0", Int32Field = 1, DoubleField = 2)]
             Named arguments
             MemberInfo: System.String StringField
             Type: 'System.String'  Value: '0'
             MemberInfo: Int32 Int32Field
             Type: 'System.Int32'  Value: '1'
             MemberInfo: Double DoubleField
             Type: 'System.Double'  Value: '2'
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((String)null)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((String)null)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((Type)null)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((Int32[])null)]
             Named arguments
    
    ...
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(ObjectField = (String)null)]
             Named arguments
             MemberInfo: System.Object ObjectField
            CustomAttributeTypedArgument.Value: null
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(StringField = null)]
             Named arguments
             MemberInfo: System.String StringField
            CustomAttributeTypedArgument.Value: null
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(Int32ArrayProperty = null)]
             Named arguments
             MemberInfo: Int32[] Int32ArrayProperty
            CustomAttributeTypedArgument.Value: null
    
    1. ni.dll prints
    Discovering: System.Reflection.Metadata.Tests
    Discovered:  System.Reflection.Metadata.Tests
    Starting:    System.Reflection.Metadata.Tests
    
    FullName: System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+HasAttributes
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+Int64Enum)-4)]  # HERE
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute("0", (Int32)1, (Double)2)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(StringField = "0", Int32Field = 1, SByteEnumArrayProperty = new System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnu
    m[1] { -1 })]
             Named arguments
             MemberInfo: System.String StringField
             Type: 'System.String'  Value: '0'
             MemberInfo: Int32 Int32Field
             Type: 'System.Int32'  Value: '1'
             MemberInfo: SByteEnum[] SByteEnumArrayProperty
             Array of 'System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnum[]':
                 Type: 'System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnum'  Value: '-1'
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute("0", (Int32)1, (Double)2, StringField = "0", Int32Field = 1, DoubleField = 2)]
             Named arguments
             MemberInfo: System.String StringField
             Type: 'System.String'  Value: '0'
             MemberInfo: Int32 Int32Field
             Type: 'System.Int32'  Value: '1'
             MemberInfo: Double DoubleField
             Type: 'System.Double'  Value: '2'
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((String)null)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((String)null)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((Type)null)]
             Named arguments
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((Int32[])null)]
             Named arguments
    
    ...
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(ObjectField = (String)null)]
             Named arguments
             MemberInfo: System.Object ObjectField
            CustomAttributeTypedArgument.Value: null
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(StringField = null)]
             Named arguments
             MemberInfo: System.String StringField
            CustomAttributeTypedArgument.Value: null
    
        [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute(Int32ArrayProperty = null)]
             Named arguments
             MemberInfo: Int32[] Int32ArrayProperty
            CustomAttributeTypedArgument.Value: null
    

    See the first custom attribute. dll prints [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute()] right while ni.dll prints [System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+TestAttribute((System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+Int64Enum)-4)] wrong.

    Need to investigate why the first custom attribute has wrong value when it is from ni.dll.

  3. YongseopKim commented on Sep 12, 2017

    @YongseopKim
    ContributorAuthor

    Difference of ILDASM between dll and ni.dll

    1. dll
    .class public auto ansi beforefieldinit System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests
           extends [System.Runtime]System.Object
    {
      .class auto ansi sealed nested private beforefieldinit HasAttributes
             extends [System.Runtime]System.Object
      {
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor() = ( 01 00 00 00 ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(string,
                                                                                                                         int32,
                                                                                                                         float64) = ( 01 00 01 30 01 00 00 00 00 00 00 00 00 00 00 40   // ...0...........@
                                                                                                                                      00 00 ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor() = ( 01 00 03 00 53 0E 0B 53 74 72 69 6E 67 46 69 65   // ....S..StringFie
                                                                                                                               6C 64 01 30 53 08 0A 49 6E 74 33 32 46 69 65 6C   // ld.0S..Int32Fiel
                                                                                                                               64 01 00 00 00 54 1D 55 4F 53 79 73 74 65 6D 2E   // d....T.UOSystem.
                                                                                                                               52 65 66 6C 65 63 74 69 6F 6E 2E 4D 65 74 61 64   // Reflection.Metad
                                                                                                                               61 74 61 2E 44 65 63 6F 64 69 6E 67 2E 54 65 73   // ata.Decoding.Tes
                                                                                                                               74 73 2E 43 75 73 74 6F 6D 41 74 74 72 69 62 75   // ts.CustomAttribu
                                                                                                                               74 65 44 65 63 6F 64 65 72 54 65 73 74 73 2B 53   // teDecoderTests+S
                                                                                                                               42 79 74 65 45 6E 75 6D 16 53 42 79 74 65 45 6E   // ByteEnum.SByteEn
                                                                                                                               75 6D 41 72 72 61 79 50 72 6F 70 65 72 74 79 01   // umArrayProperty.
                                                                                                                               00 00 00 FF ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(string,
                                                                                                                         int32,
                                                                                                                         float64) = ( 01 00 01 30 01 00 00 00 00 00 00 00 00 00 00 40   // ...0...........@
                                                                                                                                      03 00 53 0E 0B 53 74 72 69 6E 67 46 69 65 6C 64   // ..S..StringField
                                                                                                                                      01 30 53 08 0A 49 6E 74 33 32 46 69 65 6C 64 01   // .0S..Int32Field.
                                                                                                                                      00 00 00 53 0D 0B 44 6F 75 62 6C 65 46 69 65 6C   // ...S..DoubleFiel
                                                                                                                                      64 00 00 00 00 00 00 00 40 )                      // d.......@
    ...
    
    1. ni.dll
    .class public auto ansi beforefieldinit System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests
           extends [System.Runtime]System.Object
    {
      .class auto ansi sealed nested private beforefieldinit HasAttributes
             extends [System.Runtime]System.Object
      {
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(valuetype System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/Int64Enum) = ( 01 00 FC FF FF FF FF FF FF FF 00 00 ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(string,
                                                                                                                         int32,
                                                                                                                         float64) = ( 01 00 01 30 01 00 00 00 00 00 00 00 00 00 00 40   // ...0...........@
                                                                                                                                      00 00 ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor() = ( 01 00 03 00 53 0E 0B 53 74 72 69 6E 67 46 69 65   // ....S..StringFie
                                                                                                                               6C 64 01 30 53 08 0A 49 6E 74 33 32 46 69 65 6C   // ld.0S..Int32Fiel
                                                                                                                               64 01 00 00 00 54 1D 55 4F 53 79 73 74 65 6D 2E   // d....T.UOSystem.
                                                                                                                               52 65 66 6C 65 63 74 69 6F 6E 2E 4D 65 74 61 64   // Reflection.Metad
                                                                                                                               61 74 61 2E 44 65 63 6F 64 69 6E 67 2E 54 65 73   // ata.Decoding.Tes
                                                                                                                               74 73 2E 43 75 73 74 6F 6D 41 74 74 72 69 62 75   // ts.CustomAttribu
                                                                                                                               74 65 44 65 63 6F 64 65 72 54 65 73 74 73 2B 53   // teDecoderTests+S
                                                                                                                               42 79 74 65 45 6E 75 6D 16 53 42 79 74 65 45 6E   // ByteEnum.SByteEn
                                                                                                                               75 6D 41 72 72 61 79 50 72 6F 70 65 72 74 79 01   // umArrayProperty.
                                                                                                                               00 00 00 FF ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(string,
                                                                                                                         int32,
                                                                                                                         float64) = ( 01 00 01 30 01 00 00 00 00 00 00 00 00 00 00 40   // ...0...........@
                                                                                                                                      03 00 53 0E 0B 53 74 72 69 6E 67 46 69 65 6C 64   // ..S..StringField
                                                                                                                                      01 30 53 08 0A 49 6E 74 33 32 46 69 65 6C 64 01   // .0S..Int32Field.
                                                                                                                                      00 00 00 53 0D 0B 44 6F 75 62 6C 65 46 69 65 6C   // ...S..DoubleFiel
                                                                                                                                      64 00 00 00 00 00 00 00 40 )                      // d.......@
    ...
    
    # not ni
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor() = ( 01 00 00 00 ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(string,
    # ni
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(valuetype System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/Int64Enum) = ( 01 00 FC FF FF FF FF FF FF FF 00 00 ) 
        .custom instance void System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests/TestAttribute::.ctor(string,
    

    This result comes from crossgen? or roslyn?

  4. YongseopKim commented on Sep 13, 2017

    @YongseopKim
    ContributorAuthor

    I think crossgen made this results. I'll make a issue for this in coreclr.

  5. YongseopKim commented on Sep 13, 2017

    @YongseopKim
    ContributorAuthor

    I found that the problem is not the first element of CustomAtrributes but the order of CustomAttributes. I got each order of CustomAttributes.

    $ diff order.ni order.notni 
    1c1
    <     [OpenRead.Program+TestAttribute(UInt32EnumField = 3)]
    ---
    >     [OpenRead.Program+TestAttribute()]
    85c85
    <     [OpenRead.Program+TestAttribute()]
    ---
    >     [OpenRead.Program+TestAttribute(UInt32EnumField = 3)]

    As above diff shows, the contents of CustomAttributes are same to each other. The difference is just order. However the tc System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests.TestCustomAttributeDecoder supposes that the first elem of reader.GetCustomAttributes(typeDefHandle) is [Test] which has no arguments. I don't know why this happens only in case of ni, anyway, this should be fixed.

  6. YongseopKim commented on Sep 13, 2017

    @YongseopKim
    ContributorAuthor
  7. tmat commented on Nov 16, 2017

    @tmat
    Member

    @YongseopKim Sounds like a bug in NGEN to me. It should not reorder custom attributes.

  8. tmat commented on Nov 16, 2017

    @tmat
    Member

    @sergiy-k Seems like NGEN/crossgen is changing the order of custom attributes in metadata, which it should not imo.

  9. sergiy-k commented on Nov 16, 2017

    @sergiy-k
    Contributor
  10. jkotas commented on Nov 16, 2017

    @jkotas
    Member

    It may be nice if tools always preserve order of custom attributes. A lot of tools do not do it today though, e.g. ildasm/ilasm roundtrip does not preserve the order of the custom attributes either.

  11. transferred this issue fromdotnet/corefxon Jan 31, 2020
  12. added this to the Future milestone on Jan 31, 2020
  13. removed
    untriagedNew issue has not been triaged by the area owner
    on Jun 29, 2020
  14. ghost closed this as completedon Oct 28, 2022
  15. Repository owner moved this from Future to Done in Triage POD for Reflection, META, etc.on Oct 28, 2022
  16. ghost locked as resolved and limited conversation to collaborators on Nov 27, 2022
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

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions