Skip to content

Commit 3e4acf4

Browse files
authored
vtable setup fix for generic default interface methods in mono runtime (#64102)
* vtable setup fix for generic default interface methods in mono runtime When processing the overrides from interface default methods we should check if the interface class is a generic type definition first and inflate with the interface class context. Test case included. * Update test to ensure that the correct context is used
1 parent 2a1b15d commit 3e4acf4

File tree

3 files changed

+93
-3
lines changed

3 files changed

+93
-3
lines changed

src/mono/mono/metadata/class-setup-vtable.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,11 +1742,11 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
17421742
for (int i = 0; i < iface_onum; i++) {
17431743
MonoMethod *decl = iface_overrides [i*2];
17441744
MonoMethod *override = iface_overrides [i*2 + 1];
1745-
if (decl->is_inflated) {
1745+
if (mono_class_is_gtd (override->klass)) {
1746+
override = mono_class_inflate_generic_method_full_checked (override, ic, mono_class_get_context (ic), error);
1747+
} else if (decl->is_inflated) {
17461748
override = mono_class_inflate_generic_method_checked (override, mono_method_get_context (decl), error);
17471749
mono_error_assert_ok (error);
1748-
} else if (mono_class_is_gtd (override->klass)) {
1749-
override = mono_class_inflate_generic_method_full_checked (override, ic, mono_class_get_context (ic), error);
17501750
}
17511751
if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
17521752
goto fail;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// The .NET Foundation licenses this file to you under the MIT license.
2+
3+
using System;
4+
5+
// In GH issue 61244 the mono runtime aborted when inflating the default
6+
// interface method because the context used was from the base interface.
7+
8+
// The OneArgBaseInterface portion of this test handles the original bug
9+
// where the base interface has less generic arguments than the derived
10+
// interface and the runtime aborts.
11+
12+
// The SecondInterface portion of this test handles an additional scenario
13+
// where the number of generic arguments are the same in the base and
14+
// derived interface contexts, but the order is changed (or different.)
15+
// When this occurs the generic info is incorrect for the inflated method.
16+
17+
class Program
18+
{
19+
static int Main(string[] args)
20+
{
21+
return new TestClass().DoTest();
22+
}
23+
}
24+
25+
public interface OneArgBaseInterface<T1>
26+
{
27+
int SomeFunc1(T1 someParam1, Type someParam1Type);
28+
}
29+
30+
public interface TwoArgBaseInterface<T1, T2>
31+
{
32+
int SomeFunc1(T1 someParam1, T2 someParam2, Type someParam1Type, Type someParam2Type);
33+
}
34+
35+
public interface SecondInterface<TParam2Type, TParam1Type> : OneArgBaseInterface<TParam1Type>, TwoArgBaseInterface<TParam1Type, TParam2Type>
36+
{
37+
int OneArgBaseInterface<TParam1Type>.SomeFunc1(TParam1Type someParam1, Type someParam1Type)
38+
{
39+
if (typeof(TParam1Type) != someParam1Type)
40+
{
41+
Console.WriteLine("Failed => 101");
42+
return 101;
43+
}
44+
45+
return 100;
46+
}
47+
48+
int TwoArgBaseInterface<TParam1Type, TParam2Type>.SomeFunc1(TParam1Type someParam1, TParam2Type someParam2, Type someParam1Type, Type someParam2Type)
49+
{
50+
if (typeof(TParam1Type) != someParam1Type)
51+
{
52+
Console.WriteLine("Failed => 102");
53+
return 102;
54+
}
55+
56+
if (typeof(TParam2Type) != someParam2Type)
57+
{
58+
Console.WriteLine("Failed => 103");
59+
return 103;
60+
}
61+
62+
return 100;
63+
}
64+
}
65+
66+
public class TestClass : SecondInterface<int, string>
67+
{
68+
public int DoTest ()
69+
{
70+
int ret = (this as OneArgBaseInterface<string>).SomeFunc1("test string", typeof(string));
71+
if (ret != 100)
72+
return ret;
73+
74+
ret = (this as TwoArgBaseInterface<string, int>).SomeFunc1("test string", 0, typeof(string), typeof(int));
75+
if (ret != 100)
76+
return ret;
77+
78+
Console.WriteLine("Passed => 100");
79+
return 100;
80+
}
81+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
4+
<OutputType>Exe</OutputType>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="$(MSBuildProjectName).cs" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)