Skip to content

Commit

Permalink
Fixes #3072 handling intrinsics on TypeInfo (#3109)
Browse files Browse the repository at this point in the history
The problem is that GetIntrinsicIdForMethod operates on MethodDefinition but some parts of HandleCall operate on MethodReference. If the calling code references for example TypeInfo.GetMethods intrinsics detection finds this as being the GetMethods intrinsics but HandleCall doesn't and falls through to the default case which should basically never happen.

The fix is to use MethodDefinition in both places.

Added a test which needed to be done in IL since the last time TypeInfo.GetMethods existed as a method (and not inherited from Type.GetMethods) was in netstandard1.2. So in the IL the call is made to a MethodReference TypeInfo.GetMethods which reproes the problem.
  • Loading branch information
vitek-karas authored Jan 18, 2023
1 parent ae8160b commit 3521ddf
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 8 deletions.
16 changes: 8 additions & 8 deletions src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,13 @@ public static bool HandleCall (
case IntrinsicId.RuntimeHelpers_RunClassConstructor:
case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
&& calledMethod.DeclaringType.IsTypeOf (WellKnownType.System_Type)
&& calledMethod.Parameters[0].ParameterType.FullName == "System.Reflection.BindingFlags"
&& calledMethod.HasThis:
&& calledMethodDefinition.DeclaringType.IsTypeOf (WellKnownType.System_Type)
&& calledMethodDefinition.Parameters[0].ParameterType.FullName == "System.Reflection.BindingFlags"
&& calledMethodDefinition.HasThis:
case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
&& calledMethod.DeclaringType.IsTypeOf (WellKnownType.System_Type)
&& calledMethod.Parameters[0].ParameterType.IsTypeOf (WellKnownType.System_String)
&& calledMethod.HasThis:
&& calledMethodDefinition.DeclaringType.IsTypeOf (WellKnownType.System_Type)
&& calledMethodDefinition.Parameters[0].ParameterType.IsTypeOf (WellKnownType.System_String)
&& calledMethodDefinition.HasThis:
case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
|| getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
|| getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
Expand All @@ -226,7 +226,7 @@ public static bool HandleCall (
case IntrinsicId.Type_GetMethod:
case IntrinsicId.Type_GetNestedType:
case IntrinsicId.Nullable_GetUnderlyingType:
case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"):
case IntrinsicId.Expression_Property when calledMethodDefinition.HasParameterOfType (1, "System.Reflection.MethodInfo"):
case var fieldOrPropertyIntrinsic when fieldOrPropertyIntrinsic == IntrinsicId.Expression_Field || fieldOrPropertyIntrinsic == IntrinsicId.Expression_Property:
case IntrinsicId.Type_get_BaseType:
case IntrinsicId.Type_GetConstructor:
Expand Down Expand Up @@ -360,7 +360,7 @@ public static bool HandleCall (
// If we get here, we handled this as an intrinsic. As a convenience, if the code above
// didn't set the return value (and the method has a return value), we will set it to be an
// unknown value with the return type of the method.
bool returnsVoid = calledMethod.ReturnsVoid ();
bool returnsVoid = calledMethodDefinition.ReturnsVoid ();
methodReturnValue = maybeMethodReturnValue ?? (returnsVoid ?
MultiValueLattice.Top :
annotatedMethodReturnValue);
Expand Down
112 changes: 112 additions & 0 deletions test/Mono.Linker.Tests.Cases/DataFlow/Dependencies/TypeInfoCalls.il
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Metadata version: v4.0.30319
.assembly extern System.Runtime
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:0:0
}
.assembly 'library'
{
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module library.dll

// =============== CLASS MEMBERS DECLARATION ===================

.class public abstract auto ansi sealed beforefieldinit Library.TypeInfoCalls
extends [System.Runtime]System.Object
{
.method public hidebysig static void TestGetConstructors(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance class [System.Runtime]System.Reflection.ConstructorInfo[] [System.Runtime]System.Reflection.TypeInfo::GetConstructors()
IL_0007: pop
IL_0008: ret
}

.method public hidebysig static void TestGetMethods(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance class [System.Runtime]System.Reflection.MethodInfo[] [System.Runtime]System.Reflection.TypeInfo::GetMethods()
IL_0007: pop
IL_0008: ret
}

.method public hidebysig static void TestGetFields(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance class [System.Runtime]System.Reflection.FieldInfo[] [System.Runtime]System.Reflection.TypeInfo::GetFields()
IL_0007: pop
IL_0008: ret
}

.method public hidebysig static void TestGetProperties(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance class [System.Runtime]System.Reflection.PropertyInfo[] [System.Runtime]System.Reflection.TypeInfo::GetProperties()
IL_0007: pop
IL_0008: ret
}

.method public hidebysig static void TestGetEvents(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance class [System.Runtime]System.Reflection.EventInfo[] [System.Runtime]System.Reflection.TypeInfo::GetEvents()
IL_0007: pop
IL_0008: ret
}

.method public hidebysig static void TestGetNestedTypes(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance class [System.Runtime]System.Type[] [System.Runtime]System.Reflection.TypeInfo::GetNestedTypes()
IL_0007: pop
IL_0008: ret
}

.method public hidebysig static void TestGetField(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldstr "unknown"
IL_0007: callvirt instance class [System.Runtime]System.Reflection.FieldInfo [System.Runtime]System.Reflection.TypeInfo::GetField(string)
IL_000c: pop
IL_000d: ret
}

.method public hidebysig static void TestGetProperty(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldstr "unknown"
IL_0007: callvirt instance class [System.Runtime]System.Reflection.PropertyInfo [System.Runtime]System.Reflection.TypeInfo::GetProperty(string)
IL_000c: pop
IL_000d: ret
}

.method public hidebysig static void TestGetEvent(class [System.Runtime]System.Reflection.TypeInfo 'type') cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldstr "unknown"
IL_0007: callvirt instance class [System.Runtime]System.Reflection.EventInfo [System.Runtime]System.Reflection.TypeInfo::GetEvent(string)
IL_000c: pop
IL_000d: ret
}

} // end of class Library.TypeInfoCalls
47 changes: 47 additions & 0 deletions test/Mono.Linker.Tests.Cases/DataFlow/TypeInfoIntrinsics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Metadata;

namespace Mono.Linker.Tests.Cases.DataFlow
{
// Note: this test's goal is to validate that the product correctly reports unrecognized patterns
// - so the main validation is done by the ExpectedWarning attributes.
[SkipKeptItemsValidation]
[Define ("IL_ASSEMBLY_AVAILABLE")]
[SetupCompileBefore ("library.dll", new[] { "Dependencies/TypeInfoCalls.il" })]

[LogContains ("IL2070: Library.TypeInfoCalls.TestGetConstructors(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetMethods(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetFields(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetProperties(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetEvents(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetNestedTypes(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetField(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetProperty(TypeInfo)")]
[LogContains ("IL2070: Library.TypeInfoCalls.TestGetEvent(TypeInfo)")]
public class TypeInfoIntrinsics
{
public static void Main()
{
#if IL_ASSEMBLY_AVAILABLE
Library.TypeInfoCalls.TestGetConstructors(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetMethods(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetFields(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetProperties(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetEvents(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetNestedTypes(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetField(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetProperty(typeof(string).GetTypeInfo());
Library.TypeInfoCalls.TestGetEvent(typeof(string).GetTypeInfo());
#endif
}
}
}

0 comments on commit 3521ddf

Please sign in to comment.