Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2019-10-04 12:40:17 +0300
committerMarek Safar <marek.safar@gmail.com>2019-10-04 19:31:07 +0300
commite8fea0e48e63e3e5706246b28efd6ef935c5c58c (patch)
tree6652bcc6c8e8cd024da389f6e6b9e1ee9e3d7d31
parent699cea5a5b25e5fc094b89beed0fd0daca5f42e1 (diff)
Add detection for single member lookup methods in RuntimeReflectionExtensions
Fixes #55
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs226
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs63
2 files changed, 203 insertions, 86 deletions
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 8518124e8..f91f7a9c1 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -2267,14 +2267,11 @@ namespace Mono.Linker.Steps {
int first_arg_instr, second_arg_instr;
Instruction first_arg;
- string name = default;
//
// System.Type
//
if (methodCalledType.Name == "Type" && methodCalledType.Namespace == "System") {
- System.Reflection.MemberTypes memberTypes = default;
- BindingFlags bindingFlags = default;
switch (methodCalled.Name) {
//
@@ -2283,16 +2280,18 @@ namespace Mono.Linker.Steps {
// GetConstructor (BindingFlags, Binder, CallingConventions, Type [], ParameterModifier [])
//
case "GetConstructor":
- memberTypes = System.Reflection.MemberTypes.Constructor;
- goto case "Get_?_Instance";
+ if (!methodCalledDefinition.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Constructor, methodCalledDefinition, i - 1);
+
+ break;
//
// GetMethod (String)
// GetMethod (String, BindingFlags)
- // GetMethod (String, Type [])
- // GetMethod (String, Type [], ParameterModifier [])
- // GetMethod (String, BindingFlags, Binder, Type [], ParameterModifier [])
- // GetMethod (String, BindingFlags, Binder, CallingConventions, Type [], ParameterModifier [])
+ // GetMethod (String, Type[])
+ // GetMethod (String, Type[], ParameterModifier[])
+ // GetMethod (String, BindingFlags, Binder, Type[], ParameterModifier[])
+ // GetMethod (String, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
//
// TODO: .NET Core extensions
// GetMethod (String, int, Type[])
@@ -2300,92 +2299,44 @@ namespace Mono.Linker.Steps {
// GetMethod (String, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
// GetMethod (String, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
//
+ case "GetMethod":
+ if (!methodCalledDefinition.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Method, methodCalledDefinition, i - 1);
+
+ break;
+
+ //
// GetField (String)
// GetField (String, BindingFlags)
//
+ case "GetField":
+ if (!methodCalledDefinition.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Field, methodCalledDefinition, i - 1);
+
+ break;
+
+ //
// GetEvent (String)
// GetEvent (String, BindingFlags)
//
+ case "GetEvent":
+ if (!methodCalledDefinition.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Event, methodCalledDefinition, i - 1);
+
+ break;
+
+ //
// GetProperty (String)
// GetProperty (String, BindingFlags)
// GetProperty (String, Type)
- // GetProperty (String, Type [])
- // GetProperty (String, Type, Type [])
- // GetProperty (String, Type, Type [], ParameterModifier [])
- // GetProperty (String, BindingFlags, Binder, Type, Type [], ParameterModifier [])
+ // GetProperty (String, Type[])
+ // GetProperty (String, Type, Type[])
+ // GetProperty (String, Type, Type[], ParameterModifier[])
+ // GetProperty (String, BindingFlags, Binder, Type, Type[], ParameterModifier[])
//
- case "GetMethod":
- memberTypes = System.Reflection.MemberTypes.Method;
- goto case "Get_?_Instance";
- case "GetField":
- memberTypes = System.Reflection.MemberTypes.Field;
- goto case "Get_?_Instance";
- case "GetEvent":
- memberTypes = System.Reflection.MemberTypes.Event;
- goto case "Get_?_Instance";
case "GetProperty":
- memberTypes = System.Reflection.MemberTypes.Property;
- goto case "Get_?_Instance";
-
- case "Get_?_Instance":
- if (methodCalledDefinition.IsStatic)
- continue;
-
- first_arg_instr = GetInstructionAtStackDepth (instructions, i - 1, methodCalledDefinition.Parameters.Count);
- if (first_arg_instr < 0) {
- if (!HasManuallyTrackedDependency (body))
- _context.LogMessage (MessageImportance.Low, $"Reflection call '{methodCalled.FullName}' inside '{body.Method.FullName}' couldn't be decomposed");
- continue;
- }
-
- first_arg = instructions [first_arg_instr];
-
- if (memberTypes == System.Reflection.MemberTypes.Constructor) {
- if (first_arg.OpCode == OpCodes.Ldc_I4_S && methodCalled.Parameters.Count > 0 && methodCalled.Parameters [0].ParameterType.Name == "BindingFlags") {
- bindingFlags = (BindingFlags)(sbyte)first_arg.Operand;
- }
- } else {
- //
- // The next value must be string constant (we don't handle anything else)
- //
- if (first_arg.OpCode != OpCodes.Ldstr) {
- if (!HasManuallyTrackedDependency (body))
- _context.LogMessage (MessageImportance.Low, $"Reflection call '{methodCalled.FullName}' inside '{body.Method.FullName}' was detected with argument which cannot be analyzed");
- continue;
- }
-
- name = (string)first_arg.Operand;
-
- var pos_arg = instructions [first_arg_instr + 1];
- if (pos_arg.OpCode == OpCodes.Ldc_I4_S && methodCalled.Parameters.Count > 1 && methodCalled.Parameters [1].ParameterType.Name == "BindingFlags") {
- bindingFlags = (BindingFlags)(sbyte)pos_arg.Operand;
- }
- }
-
- var declaringType = FindReflectionTypeForLookup (instructions, first_arg_instr - 1);
- if (declaringType == null) {
- if (!HasManuallyTrackedDependency (body))
- _context.LogMessage (MessageImportance.Low, $"Reflection call '{methodCalled.FullName}' inside '{body.Method.FullName}' does not use detectable instance type extraction");
- continue;
- }
-
- switch (memberTypes) {
- case System.Reflection.MemberTypes.Constructor:
- MarkMethodsFromReflectionCall (declaringType, ".ctor", 0, bindingFlags);
- break;
- case System.Reflection.MemberTypes.Method:
- MarkMethodsFromReflectionCall (declaringType, name, 0, bindingFlags);
- break;
- case System.Reflection.MemberTypes.Field:
- MarkFieldsFromReflectionCall (declaringType, name);
- break;
- case System.Reflection.MemberTypes.Property:
- MarkPropertiesFromReflectionCall (declaringType, name);
- break;
- case System.Reflection.MemberTypes.Event:
- MarkEventsFromReflectionCall (declaringType, name);
- break;
- }
+ if (!methodCalledDefinition.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Property, methodCalledDefinition, i - 1);
break;
@@ -2418,7 +2369,7 @@ namespace Mono.Linker.Steps {
continue;
}
- name = (string)first_arg.Operand;
+ var name = (string)first_arg.Operand;
if (!TypeNameParser.TryParseTypeAssemblyQualifiedName (name, out string typeName, out string assemblyName))
continue;
@@ -2491,7 +2442,7 @@ namespace Mono.Linker.Steps {
continue;
}
- name = (string)second_argument.Operand;
+ var name = (string)second_argument.Operand;
MarkMethodsFromReflectionCall (declaringType, name, null, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
@@ -2562,12 +2513,115 @@ namespace Mono.Linker.Steps {
continue;
}
+
+ //
+ // System.Reflection.RuntimeReflectionExtensions
+ //
+ if (methodCalledType.Name == "RuntimeReflectionExtensions" && methodCalledType.Namespace == "System.Reflection") {
+ switch (methodCalled.Name) {
+ //
+ // GetRuntimeField (this Type type, string name)
+ //
+ case "GetRuntimeField":
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Field, methodCalledDefinition, i - 1, thisExtension: true);
+ break;
+
+ //
+ // GetRuntimeMethod (this Type type, string name, Type[] parameters)
+ //
+ case "GetRuntimeMethod":
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Method, methodCalledDefinition, i - 1, thisExtension: true);
+ break;
+
+ //
+ // GetRuntimeProperty(this Type type, string name)
+ //
+ case "GetRuntimeProperty":
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Property, methodCalledDefinition, i - 1, thisExtension: true);
+ break;
+
+ //
+ // GetRuntimeEvent(this Type type, string name)
+ //
+ case "GetRuntimeEvent":
+ ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes.Event, methodCalledDefinition, i - 1, thisExtension: true);
+ break;
+ }
+ }
}
bool HasManuallyTrackedDependency (MethodBody methodBody)
{
return PreserveDependencyLookupStep.HasPreserveDependencyAttribute (methodBody.Method);
}
+
+ //
+ // Handles instance methods called over typeof (Foo) with string name as the first argument
+ //
+ void ProcessSystemTypeGetMemberLikeCall (System.Reflection.MemberTypes memberTypes, MethodDefinition methodCalledDefinition, int startIndex, bool thisExtension = false)
+ {
+ int first_instance_arg = methodCalledDefinition.Parameters.Count;
+ if (thisExtension)
+ --first_instance_arg;
+
+ var first_arg_instr = GetInstructionAtStackDepth (instructions, startIndex, first_instance_arg);
+ if (first_arg_instr < 0 && !HasManuallyTrackedDependency (null)) {
+ if (!HasManuallyTrackedDependency (body))
+ _context.LogMessage (MessageImportance.Low, $"Reflection call '{methodCalledDefinition.FullName}' inside '{body.Method.FullName}' couldn't be decomposed");
+ return;
+ }
+
+ var first_arg = instructions [first_arg_instr];
+ BindingFlags bindingFlags= default;
+ string name = default;
+
+ if (memberTypes == System.Reflection.MemberTypes.Constructor) {
+ if (first_arg.OpCode == OpCodes.Ldc_I4_S && methodCalledDefinition.Parameters.Count > 0 && methodCalledDefinition.Parameters [0].ParameterType.Name == "BindingFlags") {
+ bindingFlags = (BindingFlags)(sbyte)first_arg.Operand;
+ }
+ } else {
+ //
+ // The next value must be string constant (we don't handle anything else)
+ //
+ if (first_arg.OpCode != OpCodes.Ldstr) {
+ if (!HasManuallyTrackedDependency (body))
+ _context.LogMessage (MessageImportance.Low, $"Reflection call '{methodCalledDefinition.FullName}' inside '{body.Method.FullName}' was detected with argument which cannot be analyzed");
+ return;
+ }
+
+ name = (string)first_arg.Operand;
+
+ var pos_arg = instructions [first_arg_instr + 1];
+ if (pos_arg.OpCode == OpCodes.Ldc_I4_S && methodCalledDefinition.Parameters.Count > 1 && methodCalledDefinition.Parameters [1].ParameterType.Name == "BindingFlags") {
+ bindingFlags = (BindingFlags)(sbyte)pos_arg.Operand;
+ }
+ }
+
+ var declaringType = FindReflectionTypeForLookup (instructions, first_arg_instr - 1);
+ if (declaringType == null) {
+ if (!HasManuallyTrackedDependency (body))
+ _context.LogMessage (MessageImportance.Low, $"Reflection call '{methodCalledDefinition.FullName}' inside '{body.Method.FullName}' does not use detectable instance type extraction");
+ return;
+ }
+
+ switch (memberTypes) {
+ case System.Reflection.MemberTypes.Constructor:
+ MarkMethodsFromReflectionCall (declaringType, ".ctor", 0, bindingFlags);
+ break;
+ case System.Reflection.MemberTypes.Method:
+ MarkMethodsFromReflectionCall (declaringType, name, 0, bindingFlags);
+ break;
+ case System.Reflection.MemberTypes.Field:
+ MarkFieldsFromReflectionCall (declaringType, name);
+ break;
+ case System.Reflection.MemberTypes.Property:
+ MarkPropertiesFromReflectionCall (declaringType, name);
+ break;
+ case System.Reflection.MemberTypes.Event:
+ MarkEventsFromReflectionCall (declaringType, name);
+ break;
+ }
+ }
}
static int GetInstructionAtStackDepth (Collection<Instruction> instructions, int startIndex, int stackSizeToBacktrace)
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs b/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs
new file mode 100644
index 000000000..16d19dad9
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs
@@ -0,0 +1,63 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using System.Reflection;
+
+namespace Mono.Linker.Tests.Cases.Reflection
+{
+ public class RuntimeReflectionExtensionsCalls
+ {
+ public static void Main ()
+ {
+ TestGetRuntimeEvent ();
+ TestGetRuntimeField ();
+ TestGetRuntimeProperty ();
+
+ TestGetRuntimeMethod ();
+ }
+
+ [Kept]
+ public static void TestGetRuntimeEvent ()
+ {
+ typeof (Foo).GetRuntimeEvent ("Event");
+ }
+
+ [Kept]
+ public static void TestGetRuntimeField ()
+ {
+ typeof (Foo).GetRuntimeField ("Field");
+ }
+
+ [Kept]
+ public static void TestGetRuntimeProperty ()
+ {
+ typeof (Foo).GetRuntimeProperty ("Property");
+ }
+
+ [Kept]
+ public static void TestGetRuntimeMethod ()
+ {
+ typeof (Foo).GetRuntimeMethod ("Method1", Type.EmptyTypes);
+ }
+
+ class Foo
+ {
+ [Kept]
+ [KeptBackingField]
+ [KeptEventAddMethod]
+ [KeptEventRemoveMethod]
+ event EventHandler<EventArgs> Event;
+
+ [Kept]
+ int Field;
+
+ [Kept]
+ [KeptBackingField]
+ public long Property { [Kept] get; [Kept] set; }
+
+ [Kept]
+ public void Method1 (int someArg)
+ {
+ }
+ }
+ }
+}