Skip to content

Cannot reflect on generic attributes whose constructors original definition uses type parameters #56492

@RikkiGibson

Description

@RikkiGibson

Related to dotnet/roslyn#55190

The following program throws CustomAttributeFormatException (using the generic-attributes feature compiler):

using System;
using System.Reflection;

class Attr<T> : Attribute { public Attr(T param) { } }

[Attr<string>("a")]
class Program
{
    static void Main()
    {
        // below line throws 'System.Reflection.CustomAttributeFormatException : Binary format of the specified custom attribute was invalid.'
        var attrs = CustomAttributeData.GetCustomAttributes(typeof(Program));
        Console.Write(attrs);
    }
}

Importantly, if we change the constructor parameter type to string, we don't get an exception. It's also worth noting that if we declare a property of a type parameter type, then specify a value for it at the usage of the attribute, we decode it just fine.

The compiler produces this IL for the type Program:

.class private auto ansi beforefieldinit Program
	extends [netstandard]System.Object
{
	.custom instance void class Attr`1<string>::.ctor(!0) = (
		01 00 01 61 00 00
	)
	// Methods
	.method private hidebysig static 
		void Main () cil managed 
	{
		// Method begins at RVA 0x2058
		// Code size 21 (0x15)
		.maxstack 8
		IL_0000: ldtoken Program
		IL_0005: call class [netstandard]System.Type [netstandard]System.Type::GetTypeFromHandle(valuetype [netstandard]System.RuntimeTypeHandle)
		IL_000a: call class [netstandard]System.Collections.Generic.IList`1<class [netstandard]System.Reflection.CustomAttributeData> [netstandard]System.Reflection.CustomAttributeData::GetCustomAttributes(class [netstandard]System.Reflection.MemberInfo)
		IL_000f: call void [netstandard]System.Console::Write(object)
		IL_0014: ret
	} // end of method Program::Main
	.method public hidebysig specialname rtspecialname 
		instance void .ctor () cil managed 
	{
		// Method begins at RVA 0x206e
		// Code size 7 (0x7)
		.maxstack 8
		IL_0000: ldarg.0
		IL_0001: call instance void [netstandard]System.Object::.ctor()
		IL_0006: ret
	} // end of method Program::.ctor
} // end of class Program

§II.21 Custom attributes in ECMA 335 reads:

Custom attributes are declared using the directive .custom, followed by the method declaration for a type constructor, optionally followed by a Bytes in parentheses:

CustomDecl ::=
Ctor [ '=' '(' Bytes ')' ]

The Ctor item represents a method declaration §II.15.4, specific for the case where the method's name is .ctor.

It seems like for the feature "generic attributes" to work properly it is necessary for the Ctor item to represent a method reference rather than a method declaration, because the method in question could be contained in a constructed type. However, I am not sure I comprehend the finer points of the spec here.

Actually, I am not sure if what I am observing is a compiler bug, or a coreclr bug, or a spec issue. Poking around the compiler's emit of the attribute constructor, it does seem to be simply producing a reference to the constructed method symbol.

cc @jkotas @AviAvni

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions