From e6cee0ea88f8826400a7be0b36d6b5cf86345187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 15 Nov 2024 20:02:14 +0100 Subject: [PATCH 1/2] Fix obtaining type handles of IDynamicInterfaceCastableImplementation Fixes #109496. We try to optimize away type handles (MethodTables) of types that are only needed due to metadata. Trying to grab type handle of such type throws. This fixes it by unconditionally generating type handles of IDynamicInterfaceCastableImplementation. --- .../DependencyAnalysis/TypeMetadataNode.cs | 12 +++++ .../SmokeTests/UnitTests/Interfaces.cs | 54 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs index 6ae29da0e6d229..7adf7531e3bb2b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs @@ -132,6 +132,18 @@ public static void GetMetadataDependencies(ref DependencyList dependencies, Node default: Debug.Assert(type.IsDefType); + // We generally postpone creating MethodTables until absolutely needed. + // IDynamicInterfaceCastableImplementation is special in the sense that just obtaining a System.Type + // (by e.g. browsing custom attribute metadata) gives the user enough to pass this to runtime APIs + // that need a MethodTable. We don't have a legitimate type handle without the MethodTable. Other + // kinds of APIs that expect a MethodTable have enough dataflow annotation to trigger warnings. + // There's no dataflow annotations on the IDynamicInterfaceCastable.GetInterfaceImplementation API. + if (type.IsInterface && ((MetadataType)type).IsDynamicInterfaceCastableImplementation()) + { + dependencies ??= new DependencyList(); + dependencies.Add(nodeFactory.ReflectedType(type), "Reflected IDynamicInterfaceCastableImplementation"); + } + TypeDesc typeDefinition = type.GetTypeDefinition(); if (typeDefinition != type) { diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs index 6a2ce7011def24..9fe1d22ace060f 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs @@ -60,6 +60,7 @@ public static int Run() TestDefaultDynamicStaticNonGeneric.Run(); TestDefaultDynamicStaticGeneric.Run(); TestDynamicStaticGenericVirtualMethods.Run(); + TestRuntime109496Regression.Run(); return Pass; } @@ -1890,4 +1891,57 @@ public static void Run() Console.WriteLine(s_entry.Enter1>("One")); } } + + class TestRuntime109496Regression + { + class CastableThing : IDynamicInterfaceCastable + { + RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(RuntimeTypeHandle interfaceType) + => Type.GetTypeFromHandle(interfaceType).GetCustomAttribute().TheType.TypeHandle; + bool IDynamicInterfaceCastable.IsInterfaceImplemented(RuntimeTypeHandle interfaceType, bool throwIfNotImplemented) + => Type.GetTypeFromHandle(interfaceType).IsDefined(typeof(TypeAttribute)); + } + + [Type(typeof(IMyInterfaceImpl))] + interface IMyInterface + { + int Method(); + } + + [DynamicInterfaceCastableImplementation] + interface IMyInterfaceImpl : IMyInterface + { + int IMyInterface.Method() => 42; + } + + [Type(typeof(IMyGenericInterfaceImpl))] + interface IMyGenericInterface + { + int Method(); + } + + [DynamicInterfaceCastableImplementation] + interface IMyGenericInterfaceImpl : IMyGenericInterface + { + int IMyGenericInterface.Method() => typeof(T).Name.Length; + } + + class TypeAttribute : Attribute + { + public Type TheType { get; } + + public TypeAttribute(Type t) => TheType = t; + } + + public static void Run() + { + object o = new CastableThing(); + + if (((IMyInterface)o).Method() != 42) + throw new Exception(); + + if (((IMyGenericInterface)o).Method() != 5) + throw new Exception(); + } + } } From 0302263a7f59a9662fac42717342054d222c6ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 15 Nov 2024 11:47:10 -0800 Subject: [PATCH 2/2] Update Interfaces.cs --- src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs index 9fe1d22ace060f..e466718d3f176c 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs @@ -4,6 +4,7 @@ using System; using System.Text; using System.Collections.Generic; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis;