From 95053af1fcf7294d18b02d61fc915027be9e4aec Mon Sep 17 00:00:00 2001 From: Marco Persson Date: Fri, 18 Nov 2022 11:06:44 +0100 Subject: [PATCH] Fix that method resolution would consider all function-pointers to be the same --- Mono.Cecil/MetadataResolver.cs | 29 +++++++++++++++++ Test/Mono.Cecil.Tests/MethodTests.cs | 47 +++++++++++++++++++++++++++- Test/Resources/il/others.il | 17 +++++++++- 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/Mono.Cecil/MetadataResolver.cs b/Mono.Cecil/MetadataResolver.cs index 95d900726..5288006c6 100644 --- a/Mono.Cecil/MetadataResolver.cs +++ b/Mono.Cecil/MetadataResolver.cs @@ -334,6 +334,35 @@ static bool AreSame (TypeSpecification a, TypeSpecification b) if (a.IsArray) return AreSame ((ArrayType) a, (ArrayType) b); + if (a.IsFunctionPointer) + return AreSame ((FunctionPointerType) a, (FunctionPointerType) b); + + return true; + } + + static bool AreSame (FunctionPointerType a, FunctionPointerType b) + { + if (a.HasThis != b.HasThis) + return false; + + if (a.CallingConvention != b.CallingConvention) + return false; + + if (!AreSame (a.ReturnType, b.ReturnType)) + return false; + + if (a.ContainsGenericParameter != b.ContainsGenericParameter) + return false; + + if (a.HasParameters != b.HasParameters) + return false; + + if (!a.HasParameters) + return true; + + if (!AreSame (a.Parameters, b.Parameters)) + return false; + return true; } diff --git a/Test/Mono.Cecil.Tests/MethodTests.cs b/Test/Mono.Cecil.Tests/MethodTests.cs index cef897dd2..8a3fa1286 100644 --- a/Test/Mono.Cecil.Tests/MethodTests.cs +++ b/Test/Mono.Cecil.Tests/MethodTests.cs @@ -3,7 +3,7 @@ using Mono.Cecil; using Mono.Cecil.Metadata; - +using Mono.Collections.Generic; using NUnit.Framework; namespace Mono.Cecil.Tests { @@ -236,5 +236,50 @@ public void InstanceAndStaticMethodComparison () Assert.AreNotEqual(instance_method, static_method_reference.Resolve ()); }); } + + [Test] + public void FunctionPointerArgumentOverload () + { + TestIL ("others.il", module => { + var others = module.GetType ("Others"); + var overloaded_methods = others.Methods.Where (m => m.Name == "OverloadedWithFpArg").ToArray (); + // Manually create the function-pointer type so `AreSame` won't exit early due to reference equality + var overloaded_method_int_reference = new MethodReference ("OverloadedWithFpArg", module.TypeSystem.Void, others) + { + HasThis = false, + Parameters = { new ParameterDefinition ("X", ParameterAttributes.None, new FunctionPointerType () { + HasThis = false, + ReturnType = module.TypeSystem.Int32, + Parameters = { new ParameterDefinition (module.TypeSystem.Int32) } + }) } + }; + + var overloaded_method_long_reference = new MethodReference ("OverloadedWithFpArg", module.TypeSystem.Void, others) + { + HasThis = false, + Parameters = { new ParameterDefinition ("X", ParameterAttributes.None, new FunctionPointerType () { + HasThis = false, + ReturnType = module.TypeSystem.Int32, + Parameters = { new ParameterDefinition (module.TypeSystem.Int64) } + }) } + }; + + var overloaded_method_cdecl_reference = new MethodReference ("OverloadedWithFpArg", module.TypeSystem.Void, others) + { + HasThis = false, + Parameters = { new ParameterDefinition ("X", ParameterAttributes.None, new FunctionPointerType () { + CallingConvention = MethodCallingConvention.C, + HasThis = false, + ReturnType = module.TypeSystem.Int32, + Parameters = { new ParameterDefinition (module.TypeSystem.Int32) } + }) } + }; + + + Assert.AreEqual (overloaded_methods[0], overloaded_method_int_reference.Resolve ()); + Assert.AreEqual (overloaded_methods[1], overloaded_method_long_reference.Resolve ()); + Assert.AreEqual (overloaded_methods[2], overloaded_method_cdecl_reference.Resolve ()); + }); + } } } diff --git a/Test/Resources/il/others.il b/Test/Resources/il/others.il index 22691a2d2..7be104208 100644 --- a/Test/Resources/il/others.il +++ b/Test/Resources/il/others.il @@ -78,7 +78,22 @@ .other instance void Others::dang_Handler (class [mscorlib]System.EventHandler) .other instance void Others::fang_Handler (class [mscorlib]System.EventHandler) } - + + .method public static void OverloadedWithFpArg(method int32 *(int32) X) cil managed + { + ret + } + + .method public static void OverloadedWithFpArg(method int32 *(int64) X) cil managed + { + ret + } + + .method public static void OverloadedWithFpArg(method unmanaged cdecl int32 *(int32) X) cil managed + { + ret + } + .method public instance void SameMethodNameInstanceStatic() cil managed { ret