Skip to content

Commit 5734a23

Browse files
authored
Fix value type unboxing bug (#69815)
1 parent cb1fd54 commit 5734a23

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

src/coreclr/vm/comdelegate.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,6 +2158,7 @@ FCIMPL1(ReflectMethodObject *, COMDelegate::FindMethodHandle, Object* refThisIn)
21582158
HELPER_METHOD_FRAME_BEGIN_RET_1(refThis);
21592159

21602160
pMD = GetMethodDesc(refThis);
2161+
pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, TypeHandle(pMD->GetMethodTable()), pMD->GetMethodInstantiation());
21612162
pRet = pMD->GetStubMethodInfo();
21622163
HELPER_METHOD_FRAME_END();
21632164

src/coreclr/vm/genmeth.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,12 +1236,11 @@ MethodDesc::FindOrCreateAssociatedMethodDesc(MethodDesc* pDefMD,
12361236
if (methodInst.GetNumArgs() != pMethod->GetNumGenericMethodArgs())
12371237
COMPlusThrow(kArgumentException);
12381238

1239-
// we base the creation of an unboxing stub on whether the original method was one already
1240-
// that keeps the reflection logic the same for value types
1239+
// we need unboxing stubs for virtual methods on value types
12411240
pInstMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
12421241
pMethod,
12431242
pMT,
1244-
pMethod->IsUnboxingStub(),
1243+
instType.IsValueType() && pMethod->IsVirtual(),
12451244
methodInst,
12461245
FALSE, /* no allowInstParam */
12471246
TRUE /* force remotable method (i.e. inst wrappers for non-generic methods on generic interfaces) */);
@@ -1263,12 +1262,8 @@ MethodDesc::FindOrCreateAssociatedMethodDesc(MethodDesc* pDefMD,
12631262
// - non generic method on a generic interface
12641263
//
12651264

1266-
// we base the creation of an unboxing stub on whether the original method was one already
1267-
// that keeps the reflection logic the same for value types
1268-
12691265
// we need unboxing stubs for virtual methods on value types unless the method is generic
1270-
BOOL fNeedUnboxingStub = pMethod->IsUnboxingStub() ||
1271-
( instType.IsValueType() && pMethod->IsVirtual() );
1266+
BOOL fNeedUnboxingStub = instType.IsValueType() && pMethod->IsVirtual();
12721267

12731268
pInstMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
12741269
pMethod, /* the original MD */

src/libraries/System.Runtime/tests/System/DelegateTests.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.IO;
5+
using System.Linq.Expressions;
56
using System.Reflection;
67
using System.Runtime.CompilerServices;
78
using System.Runtime.InteropServices;
@@ -435,6 +436,50 @@ private static void IntIntMethod(int expected, int actual)
435436
Assert.Equal(expected, actual);
436437
}
437438

439+
[Fact]
440+
public static void SameMethodObtainedViaDelegateAndReflectionAreSameForClass()
441+
{
442+
var m1 = ((MethodCallExpression)((Expression<Action>)(() => new Class().M())).Body).Method;
443+
var m2 = new Action(new Class().M).Method;
444+
Assert.True(m1.Equals(m2));
445+
}
446+
447+
[Fact]
448+
public static void SameMethodObtainedViaDelegateAndReflectionAreSameForStruct()
449+
{
450+
var m1 = ((MethodCallExpression)((Expression<Action>)(() => new Struct().M())).Body).Method;
451+
var m2 = new Action(new Struct().M).Method;
452+
Assert.True(m1.Equals(m2));
453+
}
454+
455+
[Fact]
456+
public static void SameGenericMethodObtainedViaDelegateAndReflectionAreSameForClass()
457+
{
458+
var m1 = ((MethodCallExpression)((Expression<Action>)(() => new ClassG().M<string, object>())).Body).Method;
459+
var m2 = new Action(new ClassG().M<string, object>).Method;
460+
Assert.True(m1.Equals(m2));
461+
Assert.True(m1.GetHashCode().Equals(m2.GetHashCode()));
462+
Assert.Equal(m1.MethodHandle.Value, m2.MethodHandle.Value);
463+
}
464+
465+
[Fact]
466+
public static void SameGenericMethodObtainedViaDelegateAndReflectionAreSameForStruct()
467+
{
468+
var m1 = ((MethodCallExpression)((Expression<Action>)(() => new StructG().M<string, object>())).Body).Method;
469+
var m2 = new Action(new StructG().M<string, object>).Method;
470+
Assert.True(m1.Equals(m2));
471+
Assert.True(m1.GetHashCode().Equals(m2.GetHashCode()));
472+
Assert.Equal(m1.MethodHandle.Value, m2.MethodHandle.Value);
473+
}
474+
475+
class Class { internal void M() { } }
476+
477+
struct Struct { internal void M() { } }
478+
479+
class ClassG { internal void M<Key, Value>() { } }
480+
481+
struct StructG { internal void M<Key, Value>() { } }
482+
438483
private delegate void IntIntDelegate(int expected, int actual);
439484
private delegate void IntIntDelegateWithDefault(int expected, int actual = 7);
440485

0 commit comments

Comments
 (0)