From aed318f115b8333826a3574d1163c1590674b237 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 9 Nov 2022 01:16:43 -0500 Subject: [PATCH 1/2] [mono] Fix support for generic custom attributes. Fixes https://github.com/dotnet/runtime/issues/77047. --- .../src/System/Reflection/CustomAttribute.cs | 27 +++++++------ src/mono/mono/metadata/custom-attrs.c | 38 ++++++++++++++++--- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs index 049a06bd0817c..00abf6c9cfddc 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs @@ -136,6 +136,14 @@ internal static object[] GetCustomAttributesBase(ICustomAttributeProvider obj, T return attrs; } + private static bool AttrTypeMatches(Type? attributeType, Type attrType) + { + if (attributeType == null) + return true; + return attributeType.IsAssignableFrom(attrType) || + (attributeType.IsGenericTypeDefinition && attrType.IsGenericType && attributeType.IsAssignableFrom(attrType.GetGenericTypeDefinition())); + } + internal static object[] GetCustomAttributes(ICustomAttributeProvider obj, Type attributeType, bool inherit) { ArgumentNullException.ThrowIfNull(obj); @@ -160,7 +168,7 @@ internal static object[] GetCustomAttributes(ICustomAttributeProvider obj, Type if (res[0] == null) throw new CustomAttributeFormatException("Invalid custom attribute format"); - if (attributeType != null) + if (attributeType != null && !attributeType.IsGenericTypeDefinition) { if (attributeType.IsAssignableFrom(res[0].GetType())) { @@ -219,13 +227,11 @@ internal static object[] GetCustomAttributes(ICustomAttributeProvider obj, Type if (attr == null) throw new CustomAttributeFormatException("Invalid custom attribute format"); - Type attrType = attr.GetType(); - if (attributeType != null && !attributeType.IsAssignableFrom(attrType)) - continue; - a.Add(attr); + if (AttrTypeMatches(attributeType, attr.GetType())) + a.Add(attr); } - if (attributeType == null || attributeType.IsValueType) + if (attributeType == null || attributeType.IsValueType || attributeType.IsGenericTypeDefinition) array = new Attribute[a.Count]; else array = (Array.CreateInstance(attributeType, a.Count) as object[])!; @@ -247,11 +253,8 @@ internal static object[] GetCustomAttributes(ICustomAttributeProvider obj, Type throw new CustomAttributeFormatException("Invalid custom attribute format"); Type attrType = attr.GetType(); - if (attributeType != null) - { - if (!attributeType.IsAssignableFrom(attrType)) - continue; - } + if (!AttrTypeMatches(attributeType, attr.GetType())) + continue; AttributeInfo? firstAttribute; if (attributeInfos.TryGetValue(attrType, out firstAttribute)) @@ -284,7 +287,7 @@ internal static object[] GetCustomAttributes(ICustomAttributeProvider obj, Type } } while (btype != null); - if (attributeType == null || attributeType.IsValueType) + if (attributeType == null || attributeType.IsValueType || attributeType.IsGenericTypeDefinition) array = new Attribute[a.Count]; else array = (Array.CreateInstance(attributeType, a.Count) as object[])!; diff --git a/src/mono/mono/metadata/custom-attrs.c b/src/mono/mono/metadata/custom-attrs.c index 2bce3b3e79781..d8fda30d4ce6e 100644 --- a/src/mono/mono/metadata/custom-attrs.c +++ b/src/mono/mono/metadata/custom-attrs.c @@ -1770,6 +1770,13 @@ create_custom_attr_data_into_array (MonoImage *image, MonoCustomAttrEntry *cattr HANDLE_FUNCTION_RETURN (); } +static gboolean +cattr_class_match (MonoClass *attr_klass, MonoClass *klass) +{ + return mono_class_is_assignable_from_internal (attr_klass, klass) || + (m_class_is_gtd (attr_klass) && m_class_is_ginst (klass) && mono_class_is_assignable_from_internal (attr_klass, mono_class_get_generic_type_definition (klass))); +} + static MonoArrayHandle mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error) { @@ -1795,7 +1802,7 @@ mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_ for (i = 0; i < cinfo->num_attrs; ++i) { MonoMethod *ctor = cinfo->attrs[i].ctor; g_assert (ctor); - if (mono_class_is_assignable_from_internal (attr_klass, ctor->klass)) + if (cattr_class_match (attr_klass, ctor->klass)) n++; } } else { @@ -1807,7 +1814,7 @@ mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_ n = 0; for (i = 0; i < cinfo->num_attrs; ++i) { MonoCustomAttrEntry *centry = &cinfo->attrs [i]; - if (!attr_klass || mono_class_is_assignable_from_internal (attr_klass, centry->ctor->klass)) { + if (!attr_klass || cattr_class_match (attr_klass, centry->ctor->klass)) { create_custom_attr_into_array (cinfo->image, centry->ctor, centry->data, centry->data_size, result, n, error); goto_if_nok (error, exit); @@ -2689,10 +2696,31 @@ custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token if (assembly_token) *assembly_token = 0; return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name); + } else if (class_index == MONO_MEMBERREF_PARENT_TYPESPEC) { + ERROR_DECL (error); + + if (!image->assembly) + /* Avoid recursive calls from mono_assembly_has_reference_assembly_attribute () etc. */ + return FALSE; + + guint32 token = MONO_TOKEN_TYPE_SPEC | nindex; + MonoType *type = mono_type_get_checked (image, token, NULL, error); + if (!is_ok (error)) { + mono_error_cleanup (error); + return FALSE; + } + + MonoClass *klass = mono_class_from_mono_type_internal (type); + g_assert (klass); + if (class_name) + *class_name = m_class_get_name (klass); + if (nspace) + *nspace = m_class_get_name_space (klass); + if (assembly_token) + *assembly_token = 0; + return TRUE; } else { - /* Attributes can't be generic, so it won't be - * a typespec, and they're always - * constructors, so it won't be a moduleref */ + /* Attributes are always constructors, so it won't be a moduleref */ g_assert_not_reached (); } } else { From 572f4c9166974f8caadcd83089c2488c9b565b35 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Tue, 15 Nov 2022 16:02:24 -0500 Subject: [PATCH 2/2] Reenable tests. --- src/tests/issues.targets | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index f39b00887245e..6088017275f91 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1360,9 +1360,6 @@ https://github.com/dotnet/runtime/issues/71656 - - https://github.com/dotnet/runtime/issues/56887 - https://github.com/dotnet/runtime/issues/54176 @@ -4049,4 +4046,4 @@ Condition="'%(ExcludeList.Extension)' == '.OutOfProcessTest'" /> - \ No newline at end of file +