diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index 505bf061cd27f7..ec6745b77d0796 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -1877,7 +1877,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o flags |= MONO_ITF_OVERRIDE_EXPLICITLY_IMPLEMENTED; if (interface_is_explicitly_implemented_by_class && variant_itf) flags |= MONO_ITF_OVERRIDE_VARIANT_ITF; - if (vtable [im_slot] == NULL) + // if the slot is emtpy, or it's filled with a DIM, treat it as empty + if (vtable [im_slot] == NULL || m_class_is_interface (vtable [im_slot]->klass)) flags |= MONO_ITF_OVERRIDE_SLOT_EMPTY; if (check_interface_method_override (klass, im, cm, flags)) { TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING\n")); diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 66bdb62a52cf8b..fd7f4717fda51e 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -2686,6 +2686,8 @@ set_interface_map_data_method_object (MonoMethod *method, MonoClass *iclass, int MonoMethod* foundMethod = m_class_get_vtable (klass) [i + ioffset]; + g_assert (foundMethod); + if (mono_class_has_dim_conflicts (klass) && mono_class_is_interface (foundMethod->klass)) { GSList* conflicts = mono_class_get_dim_conflicts (klass); GSList* l; diff --git a/src/mono/sample/HelloWorld/Program.cs b/src/mono/sample/HelloWorld/Program.cs index 6d0b31d30dc6f8..3fa838c1c2a008 100644 --- a/src/mono/sample/HelloWorld/Program.cs +++ b/src/mono/sample/HelloWorld/Program.cs @@ -3,6 +3,37 @@ using System; +interface IDefault +{ + public void Method1() + { + Console.WriteLine("Interface Method1"); + } + + public object Method2() + { + Console.WriteLine("Interface Method2"); + return null; + } +} + +abstract class ClassA : IDefault +{ + virtual public void Method1() + { + Console.WriteLine("ClassA Method 1"); + } +} + +class ClassB : ClassA +{ + public virtual object Method2() + { + Console.WriteLine("ClassB Method2"); + return null; + } +} + namespace HelloWorld { internal class Program @@ -14,6 +45,12 @@ private static void Main(string[] args) Console.WriteLine(typeof(object).Assembly.FullName); Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ()); Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription); + + IDefault c = new ClassB(); + + c.Method1(); + c.Method2(); + } } -} \ No newline at end of file +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github81882.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github81882.cs new file mode 100644 index 00000000000000..1a5203922431cd --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github81882.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Linq; + +using Xunit; + +namespace LeaveAbstractMethodsNulInVTable +{ + interface IDefault + { + public string Method1() => "Interface Method1"; + + public string Method2() => "Interface Method2"; + } + + abstract class ClassA : IDefault + { + virtual public string Method1() => "ClassA Method1"; + } + + class ClassB : ClassA + { + virtual public string Method2() => "ClassB Method2"; + } + + public class Program + { + public static int Main() + { + IDefault c = new ClassB(); + + string s1 = c.Method1(); + Assert.Equal("ClassA Method1", s1); + + string s2 = c.Method2(); + Assert.Equal("ClassB Method2", s2); + + return 100; + } + } + +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github81882.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github81882.csproj new file mode 100644 index 00000000000000..42c7a9e8ffc90f --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github81882.csproj @@ -0,0 +1,9 @@ + + + true + Exe + + + + +