-
Notifications
You must be signed in to change notification settings - Fork 5.2k
System.Reflection.CustomAttributeFormatException thrown on a retrieval of derived attribute with overridden property getter #117584
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
base: main
Are you sure you want to change the base?
Conversation
…l of derived attribute with overridden property getter
@@ -107,7 +107,7 @@ public static Attribute Instantiate(this CustomAttributeData cad) | |||
for (; ; ) | |||
{ | |||
PropertyInfo? propertyInfo = walk.GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); | |||
if (propertyInfo != null) | |||
if (propertyInfo?.SetMethod is not null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this logic equivalent to the others, or just equivalent enough to pass the test? What corner cases are we missing in the test that necessitate the more complex logic elsewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I was going to be off for a few days so I did rapidely just enough to pass the test and not let the PR hanging, I fixed it now. The missing condition stops the lookup in base classes early if someone used the new keyword to hide the property instead of overriding it.
@AaronRobinsonMSFT Can you review this when time permits please? |
PropertyDefinition? property = GetProperty(attribute, namedArgument.Name); | ||
if (property != null) | ||
MarkMethod(property.SetMethod, reason, origin); | ||
TypeDefinition? type = attribute; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implements this for PublishTrimmed; to implement for PublishAot, the new semantic needs to be implemented here too:
Lines 237 to 278 in 09e6ddd
private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName) | |
{ | |
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition(); | |
MetadataReader reader = attributeTypeDefinition.MetadataReader; | |
var typeDefinition = reader.GetTypeDefinition(attributeTypeDefinition.Handle); | |
foreach (PropertyDefinitionHandle propDefHandle in typeDefinition.GetProperties()) | |
{ | |
PropertyDefinition propDef = reader.GetPropertyDefinition(propDefHandle); | |
if (reader.StringComparer.Equals(propDef.Name, propertyName)) | |
{ | |
PropertyAccessors accessors = propDef.GetAccessors(); | |
if (!accessors.Setter.IsNil) | |
{ | |
MethodDesc setterMethod = (MethodDesc)attributeTypeDefinition.EcmaModule.GetObject(accessors.Setter); | |
if (factory.MetadataManager.IsReflectionBlocked(setterMethod)) | |
return false; | |
// Method on a generic attribute | |
if (attributeType != attributeTypeDefinition) | |
{ | |
setterMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(setterMethod, (InstantiatedType)attributeType); | |
} | |
dependencies.Add(factory.ReflectedMethod(setterMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Custom attribute blob"); | |
} | |
return true; | |
} | |
} | |
// Haven't found it in current type. Check the base type. | |
TypeDesc baseType = attributeType.BaseType; | |
if (baseType != null) | |
return AddDependenciesFromPropertySetter(dependencies, factory, baseType, propertyName); | |
// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation. | |
return true; | |
} |
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
Outdated
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
Outdated
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
Outdated
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you!
@MichalStrehovsky Any further feedback?
If we really want this, it looks reasonable. For posterity though, this is implementing some of C# language semantics into the runtime reflection stack (the runtime reflection stack doesn't consider property inheritance in general, like I pointed out in #110945 (comment), or how IL is more expressible than what C# allows. C# can sometimes get into IL-level corner cases due to NuGet versioning and compile-time seeing different things than runtime. What is implemented here will allow things like: [Derived(Prop = 123)]
class Program;
class BaseAttribute : Attribute
{
public virtual int Prop { get; set; }
}
class DerivedAttribute : BaseAttribute
{
// Note `new` keyword
public new virtual int Prop { get => base.Prop; }
} to work even though the C# compiler would not accept this. Hopefully this is sufficiently leafy within the reflection stack that it won't affect many things. I'm not worried about this breaking existing apps (because we're just fixing a throw to not throw). However there's is an aspect that if someone does take advantage of this not throwing, they may run into new issues that we didn't consider. Like I wrote in #110945 (comment) this needed a bit more design discussion to consider these things before we decide whether we really want to fix this. |
Fixes #110412
Sorry for the delay, I've been busy these last weeks