From 4da12e91593618cbc95c4ec70fa0b288a6daf1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 24 Jan 2023 14:04:36 +0900 Subject: [PATCH 1/4] Avoid GetConstructors in constraint validation Avoids bringing ConstructorInfo to simple apps. --- .../TypeLoader/ConstraintValidatorSupport.cs | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs index 76e62e41bb8aa8..8b81f5f64f7013 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs @@ -6,6 +6,9 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; +using System.Reflection.Runtime.General; + +using Internal.Reflection.Core.Execution; using Debug = global::System.Diagnostics.Debug; @@ -287,11 +290,47 @@ private static bool HasExplicitOrImplicitPublicDefaultConstructor(this Type type if (type.IsValueType) return true; - foreach (var ctor in type.GetConstructors()) + // Look for a public parameterless constructor. Avoid Type.GetConstructors() so that we don't + // bring ConstructorInfo support into apps that don't use reflection. + + RuntimeTypeHandle typeHandle = type.TypeHandle; + + QTypeDefinition qTypeDefinition; + if (!ReflectionExecution.ExecutionEnvironment.TryGetMetadataForNamedType(typeHandle, out qTypeDefinition)) + { + // Could be an array, reflection blocked type or something similar. + return false; + } + + if (qTypeDefinition.IsNativeFormatMetadataBased) { - if (!ctor.IsStatic && ctor.IsPublic && ctor.GetParametersNoCopy().Length == 0) - return true; + var reader = qTypeDefinition.NativeFormatReader; + foreach (var methodHandle in reader.GetTypeDefinition(qTypeDefinition.NativeFormatHandle).Methods) + { + var method = reader.GetMethod(methodHandle); + const MethodAttributes specialNameAttributes = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName; + if ((method.Flags & specialNameAttributes) == specialNameAttributes + && (method.Flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Public + && (method.Flags & MethodAttributes.Static) == 0) + { + var sig = reader.GetMethodSignature(method.Signature); + if (sig.Parameters.Count == 0 && method.Name.StringEquals(".ctor", reader)) + { + return true; + } + } + } + } + +#if ECMA_METADATA_SUPPORT + if (qTypeDefinition.IsEcmaFormatMetadataBased) + { + foreach (var ctor in type.GetConstructors()) + if (!ctor.IsStatic && ctor.IsPublic && ctor.GetParametersNoCopy().Length == 0) + return true; } +#endif + return false; } From 3ec2f2d5cf5498542c1391c265b56a3b7f411842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 24 Jan 2023 14:40:41 +0900 Subject: [PATCH 2/4] Revert "Avoid GetConstructors in constraint validation" This reverts commit 4da12e91593618cbc95c4ec70fa0b288a6daf1ee. --- .../TypeLoader/ConstraintValidatorSupport.cs | 45 ++----------------- 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs index 8b81f5f64f7013..76e62e41bb8aa8 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidatorSupport.cs @@ -6,9 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; -using System.Reflection.Runtime.General; - -using Internal.Reflection.Core.Execution; using Debug = global::System.Diagnostics.Debug; @@ -290,47 +287,11 @@ private static bool HasExplicitOrImplicitPublicDefaultConstructor(this Type type if (type.IsValueType) return true; - // Look for a public parameterless constructor. Avoid Type.GetConstructors() so that we don't - // bring ConstructorInfo support into apps that don't use reflection. - - RuntimeTypeHandle typeHandle = type.TypeHandle; - - QTypeDefinition qTypeDefinition; - if (!ReflectionExecution.ExecutionEnvironment.TryGetMetadataForNamedType(typeHandle, out qTypeDefinition)) - { - // Could be an array, reflection blocked type or something similar. - return false; - } - - if (qTypeDefinition.IsNativeFormatMetadataBased) + foreach (var ctor in type.GetConstructors()) { - var reader = qTypeDefinition.NativeFormatReader; - foreach (var methodHandle in reader.GetTypeDefinition(qTypeDefinition.NativeFormatHandle).Methods) - { - var method = reader.GetMethod(methodHandle); - const MethodAttributes specialNameAttributes = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName; - if ((method.Flags & specialNameAttributes) == specialNameAttributes - && (method.Flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Public - && (method.Flags & MethodAttributes.Static) == 0) - { - var sig = reader.GetMethodSignature(method.Signature); - if (sig.Parameters.Count == 0 && method.Name.StringEquals(".ctor", reader)) - { - return true; - } - } - } - } - -#if ECMA_METADATA_SUPPORT - if (qTypeDefinition.IsEcmaFormatMetadataBased) - { - foreach (var ctor in type.GetConstructors()) - if (!ctor.IsStatic && ctor.IsPublic && ctor.GetParametersNoCopy().Length == 0) - return true; + if (!ctor.IsStatic && ctor.IsPublic && ctor.GetParametersNoCopy().Length == 0) + return true; } -#endif - return false; } From 1f0b3dc6b44cbccc40782016cd075eac06ef0da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 24 Jan 2023 15:18:15 +0900 Subject: [PATCH 3/4] Different approach --- .../Core/Execution/ExecutionEnvironment.cs | 1 + .../General/TypeResolver.NativeFormat.cs | 2 +- .../Reflection/Runtime/General/TypeUnifier.cs | 19 ++++++++++++++----- .../Runtime/TypeInfos/RuntimeTypeInfo.cs | 2 +- ...EnvironmentImplementation.MappingTables.cs | 13 +++++++++++++ .../ReflectionDomainSetupImplementation.cs | 2 +- 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs index e42fbeea9dfd2d..5526ffdac3a5c5 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs @@ -71,6 +71,7 @@ public abstract class ExecutionEnvironment public abstract bool TryGetByRefTypeTargetType(RuntimeTypeHandle byRefTypeHandle, out RuntimeTypeHandle targetTypeHandle); public abstract bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle); + public abstract bool TryGetConstructedGenericTypeForComponentsNoConstraintCheck(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle); //============================================================================================== // Invoke and field access support. diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs index e6b89326e13cde..3051f2e4c0ec90 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs @@ -133,7 +133,7 @@ internal static RuntimeTypeInfo ResolveTypeDefinition(this TypeDefinitionHandle return null; genericTypeArguments.Add(genericTypeArgument); } - return genericTypeDefinition.GetConstructedGenericType(genericTypeArguments.ToArray()); + return genericTypeDefinition.GetConstructedGenericTypeNoConstraintCheck(genericTypeArguments.ToArray()); } case HandleType.TypeReference: diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs index c118a02ec481b3..be595d933de95f 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs @@ -85,9 +85,9 @@ public static RuntimeTypeInfo GetPointerType(this RuntimeTypeInfo targetType) return RuntimePointerTypeInfo.GetPointerTypeInfo(targetType); } - public static RuntimeTypeInfo GetConstructedGenericType(this RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) + public static RuntimeTypeInfo GetConstructedGenericTypeNoConstraintCheck(this RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) { - return RuntimeConstructedGenericTypeInfo.GetRuntimeConstructedGenericTypeInfo(genericTypeDefinition, genericTypeArguments); + return RuntimeConstructedGenericTypeInfo.GetRuntimeConstructedGenericTypeInfoNoConstraintCheck(genericTypeDefinition, genericTypeArguments); } public static RuntimeTypeInfo GetConstructedGenericTypeWithTypeHandle(this RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) @@ -396,7 +396,14 @@ internal sealed partial class RuntimeConstructedGenericTypeInfo : RuntimeTypeInf { internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTypeInfo(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) { - return GetRuntimeConstructedGenericTypeInfo(genericTypeDefinition, genericTypeArguments, precomputedTypeHandle: GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments)); + RuntimeTypeHandle precomputedTypeHandle = GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments, ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponents); + return GetRuntimeConstructedGenericTypeInfo(genericTypeDefinition, genericTypeArguments, precomputedTypeHandle); + } + + internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTypeInfoNoConstraintCheck(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) + { + RuntimeTypeHandle precomputedTypeHandle = GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments, ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponentsNoConstraintCheck); + return GetRuntimeConstructedGenericTypeInfo(genericTypeDefinition, genericTypeArguments, precomputedTypeHandle); } internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTypeInfo(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments, RuntimeTypeHandle precomputedTypeHandle) @@ -407,7 +414,9 @@ internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTy return typeInfo; } - private static RuntimeTypeHandle GetRuntimeTypeHandleIfAny(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) + delegate bool TryGetConstructedGenericTypeDelegate(RuntimeTypeHandle genericDefinition, RuntimeTypeHandle[] genericArguments, out RuntimeTypeHandle result); + + private static RuntimeTypeHandle GetRuntimeTypeHandleIfAny(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments, TryGetConstructedGenericTypeDelegate constructor) { RuntimeTypeHandle genericTypeDefinitionHandle = genericTypeDefinition.InternalTypeHandleIfAvailable; if (genericTypeDefinitionHandle.IsNull()) @@ -427,7 +436,7 @@ private static RuntimeTypeHandle GetRuntimeTypeHandleIfAny(RuntimeTypeInfo gener } RuntimeTypeHandle typeHandle; - if (!ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out typeHandle)) + if (!constructor(genericTypeDefinitionHandle, genericTypeArgumentHandles, out typeHandle)) return default(RuntimeTypeHandle); return typeHandle; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs index 3100867a216110..b32f13dbd41505 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs @@ -478,7 +478,7 @@ public sealed override Type MakeGenericType(params Type[] typeArguments) // Desktop compatibility: Treat generic type definitions as a constructed generic type using the generic parameters as type arguments. if (runtimeTypeArgument.IsGenericTypeDefinition) - runtimeTypeArgument = runtimeTypeArguments[i] = runtimeTypeArgument.GetConstructedGenericType(runtimeTypeArgument.RuntimeGenericTypeParameters); + runtimeTypeArgument = runtimeTypeArguments[i] = runtimeTypeArgument.GetConstructedGenericTypeNoConstraintCheck(runtimeTypeArgument.RuntimeGenericTypeParameters); if (runtimeTypeArgument.IsByRefLike) throw new TypeLoadException(SR.CannotUseByRefLikeTypeInInstantiation); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs index 23d5a27efb625a..df28255b46025d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs @@ -353,6 +353,19 @@ public sealed override unsafe bool TryGetConstructedGenericTypeForComponents(Run return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle); } + + // Given a RuntimeTypeHandle for a generic type G and a set of RuntimeTypeHandles T1, T2.., return the RuntimeTypeHandle for the generic + // instance G if the pay-for-play policy denotes G as browsable. This is used to implement Type.MakeGenericType(). + // + // Preconditions: + // runtimeTypeDefinitionHandle is a valid RuntimeTypeHandle for a generic type. + // genericTypeArgumentHandles is an array of valid RuntimeTypeHandles. + // + public sealed override unsafe bool TryGetConstructedGenericTypeForComponentsNoConstraintCheck(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle) + { + return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle); + } + public sealed override MethodInvoker TryGetMethodInvoker(RuntimeTypeHandle declaringTypeHandle, QMethodDefinition methodHandle, RuntimeTypeHandle[] genericMethodTypeArgumentHandles) { MethodBase methodInfo = ReflectionCoreExecution.ExecutionDomain.GetMethod(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ReflectionDomainSetupImplementation.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ReflectionDomainSetupImplementation.cs index ce54d2fea2f6e8..0b873ee01e3391 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ReflectionDomainSetupImplementation.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ReflectionDomainSetupImplementation.cs @@ -36,7 +36,7 @@ public sealed override Exception CreateNonInvokabilityException(MemberInfo perta if (methodBase is ConstructorInfo) { Type declaringType = methodBase.DeclaringType; - if (typeof(Delegate).IsAssignableFrom(declaringType)) + if (declaringType.BaseType == typeof(MulticastDelegate)) throw new PlatformNotSupportedException(SR.PlatformNotSupported_CannotInvokeDelegateCtor); } } From e75c829514c55d150a7c9e3ade54c4a2977306a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 25 Jan 2023 10:50:53 +0900 Subject: [PATCH 4/4] Update TypeUnifier.cs --- .../src/System/Reflection/Runtime/General/TypeUnifier.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs index be595d933de95f..e9d67f2be960c3 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs @@ -394,15 +394,19 @@ protected sealed override RuntimePointerTypeInfo Factory(UnificationKey key) //----------------------------------------------------------------------------------------------------------- internal sealed partial class RuntimeConstructedGenericTypeInfo : RuntimeTypeInfo, IKeyedItem { + private static TryGetConstructedGenericTypeDelegate s_tryGetConstructedGenericTypeWithConstraintCheck; internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTypeInfo(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) { - RuntimeTypeHandle precomputedTypeHandle = GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments, ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponents); + TryGetConstructedGenericTypeDelegate del = s_tryGetConstructedGenericTypeWithConstraintCheck ??= ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponents; + RuntimeTypeHandle precomputedTypeHandle = GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments, del); return GetRuntimeConstructedGenericTypeInfo(genericTypeDefinition, genericTypeArguments, precomputedTypeHandle); } + private static TryGetConstructedGenericTypeDelegate s_tryGetConstructedGenericTypeNoConstraintCheck; internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTypeInfoNoConstraintCheck(RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments) { - RuntimeTypeHandle precomputedTypeHandle = GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments, ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponentsNoConstraintCheck); + TryGetConstructedGenericTypeDelegate del = s_tryGetConstructedGenericTypeNoConstraintCheck ??= ReflectionCoreExecution.ExecutionEnvironment.TryGetConstructedGenericTypeForComponentsNoConstraintCheck; + RuntimeTypeHandle precomputedTypeHandle = GetRuntimeTypeHandleIfAny(genericTypeDefinition, genericTypeArguments, del); return GetRuntimeConstructedGenericTypeInfo(genericTypeDefinition, genericTypeArguments, precomputedTypeHandle); }