Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ilasm does not apply multiple custom attributes on interface implementations #82373

Open
ltrzesniewski opened this issue Feb 19, 2023 · 3 comments
Labels
area-ILTools-coreclr Priority:2 Work that is important, but not critical for the release
Milestone

Comments

@ltrzesniewski
Copy link
Contributor

ltrzesniewski commented Feb 19, 2023

Description

I believe the following code:

.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 )
.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 )

is supposed to apply two attributes on the interface implementation.

When round-tripped through ilasm/ildasm, this code is turned into:

.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 ) 
.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 ) 

Which means:

  • Test1Attribute is applied on the interface implementation (metadata table 09)
  • Test2Attribute is applied on the type definition (metadata table 02)

The CustomAttribute metadata table shows that ildasm is correct here:

image

In addition, note that the following code produces the desired effect in ilasm:

.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 )
.interfaceimpl type ITestInterface
.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 )

image

But in that case, ildasm decompiles it to:

.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 ) 
.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 ) 

Which doesn't round-trip.

Reproduction Steps

Here is a test file, Test.il:

.assembly extern mscorlib
{
	.publickeytoken = ( b7 7a 5c 56 19 34 e0 89	)
	.ver 4:0:0:0
}
.assembly Test
{
	.hash algorithm 0x00008004 // SHA1
	.ver 1:0:0:0
}

.module Test.dll
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WindowsCui
.corflags 0x00000001 // ILOnly

.class private auto ansi '<Module>'
{
}

.class public auto ansi beforefieldinit TestType
    extends [mscorlib]System.Object
	implements ITestInterface
{
    .interfaceimpl type ITestInterface
    .custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 )
    .custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 )

    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    }
}

.class interface public auto ansi abstract ITestInterface
{
}

.class public auto ansi beforefieldinit Test1Attribute
    extends [mscorlib]System.Attribute
{
    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
        IL_0006: ret
    }
}

.class public auto ansi beforefieldinit Test2Attribute
    extends [mscorlib]System.Attribute
{
    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
        IL_0006: ret
    }
}
  • Compile it with ilasm /DLL Test.il
  • Decompile it with ildasm /OUT=TestOut.il Test.dll

Expected behavior

  • Both Test1Attribute and Test2Attribute should be applied on the interface implementation (metadata table 09: InterfaceImpl)
  • This shouldn't change when the code is round-tripped through ilasm/ildasm

Actual behavior

  • Test1Attribute is applied on the interface implementation (metadata table 09: InterfaceImpl)
  • Test2Attribute is applied on the type definition (metadata table 02: TypeDef)

Regression?

Not as far as I can tell.

Known Workarounds

Repeat .interfaceimpl type for each .custom instance to apply the custom attribute to the interface implementation.

No workaround for the round-trip inconsistency though.

Configuration

Tested with ilasm/ildasm from:

  • the current main: 5ac3de1
  • Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILDAsm NuGet packages v6.0.0

(why are the v7.0.0 packages empty BTW?)

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Feb 19, 2023
@ghost
Copy link

ghost commented Feb 19, 2023

Tagging subscribers to this area: @JulieLeeMSFT
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

I believe the following code:

.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 )
.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 )

is supposed to apply two attributes on the interface implementation.

When round-tripped through ilasm/ildasm, this code is turned into:

.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 ) 
.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 ) 

Which means:

  • Test1Attribute is applied on the interface implementation (metadata table 09)
  • Test2Attribute is applied on the type definition (metadata table 02)

The CustomAttribute metadata table shows that ildasm is correct here:

image

In addition, note that the following code produces the desired effect in ilasm:

.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 )
.interfaceimpl type ITestInterface
.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 )

image

But in that case, ildasm decompiles it to:

.interfaceimpl type ITestInterface
.custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 ) 
.custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 ) 

Which doesn't round-trip.

Reproduction Steps

Here is a test file, Test.il:

.assembly extern mscorlib
{
	.publickeytoken = ( b7 7a 5c 56 19 34 e0 89	)
	.ver 4:0:0:0
}
.assembly Test
{
	.hash algorithm 0x00008004 // SHA1
	.ver 1:0:0:0
}

.module Test.dll
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WindowsCui
.corflags 0x00000001 // ILOnly

.class private auto ansi '<Module>'
{
}

.class public auto ansi beforefieldinit TestType
    extends [mscorlib]System.Object
	implements ITestInterface
{
    .interfaceimpl type ITestInterface
    .custom instance void Test1Attribute::.ctor() = ( 01 00 00 00 )
    .custom instance void Test2Attribute::.ctor() = ( 01 00 00 00 )

    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    }
}

.class interface public auto ansi abstract ITestInterface
{
}

.class public auto ansi beforefieldinit Test1Attribute
    extends [mscorlib]System.Attribute
{
    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
        IL_0006: ret
    }
}

.class public auto ansi beforefieldinit Test2Attribute
    extends [mscorlib]System.Attribute
{
    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
        IL_0006: ret
    }
}
  • Compile it with ilasm /DLL Test.il
  • Decompile it with ildasm /OUT=TestOut.il Test.dll

Expected behavior

  • Both Test1Attribute and Test2Attribute should be applied on the interface implementation (metadata table 09: InterfaceImpl)
  • This shouldn't change when the code is round-tripped through ilasm/ildasm

Actual behavior

  • Test1Attribute is applied on the interface implementation (metadata table 09: InterfaceImpl)
  • Test2Attribute is applied on the type definition (metadata table 02: TypeDef)

Regression?

Not as far as I can tell.

Known Workarounds

Repeat .interfaceimpl type for each .custom instance to apply the custom attribute to the interface implementation.

No workaround for the round-trip inconsistency though.

Configuration

Tested with ilasm/ildasm from:

  • the current main: 5ac3de1
  • Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILDAsm NuGet packages v6.0.0

(why are the v7.0.0 packages empty BTW?)

Other information

No response

Author: ltrzesniewski
Assignees: -
Labels:

area-ILTools-coreclr, untriaged

Milestone: -

@JulieLeeMSFT
Copy link
Member

cc @TIHan, PTAL.

@TIHan
Copy link
Contributor

TIHan commented Mar 3, 2023

Will look at this tomorrow.

@TIHan TIHan added the Priority:2 Work that is important, but not critical for the release label Apr 24, 2023
@TIHan TIHan added this to the Future milestone Apr 24, 2023
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Apr 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-ILTools-coreclr Priority:2 Work that is important, but not critical for the release
Projects
None yet
Development

No branches or pull requests

4 participants