From 10fb50e347eefa1d1c7e0e5a10a0c483dbf62027 Mon Sep 17 00:00:00 2001 From: Scott Ferguson Date: Thu, 12 Jun 2025 12:24:33 -0400 Subject: [PATCH] Fix Crash on Default Interface Methods Call This is a port of https://github.com/dotnet/runtime/pull/115306: In case of a generic interface, build_imt_slots calculate the vt_slot to find the index in the vtable for the implementation. Currently implementation assumed interface methods are either static and/or virtual, but it's possible to have private/sealed methods that won't end up as virtual methods in vtable. This case was handled when building the vtable, but we didn't handle that scenario when building the IMT slots, ending up with wrong vtable slot, potentially outside of allocated memory. In repro provided by https://github.com/dotnet/runtime/issues/113958, the created vtable will have 5 slots, 4 from implementing Object and 1 from the implemented interface. When calculating the vt_slot in build_imt_slots we did however include the private DIM methods when calculating vtable slot, ending up with 4 + 3, slot 7, but vtable only allocated 5, so it will read outside allocated memory, and if it this turns out to be NULL, that will trigger assert, otherwise it will use random value, but since IMT slot will be patched with compiled method, the issue wouldn't manifest, at least not in the specific repro scenario. Fix makes sure we only count virtual methods in build_imt_slots vt_slot index, similar to previous fixes for static and non-virtual methods in non-generic interfaces: --- mono/metadata/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mono/metadata/object.c b/mono/metadata/object.c index dbda0db75cff..6d5e8155d5c8 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -1571,7 +1571,7 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface); if (m_method_is_static (method)) continue; - if (mono_method_get_imt_slot (method) != slot_num) { + if (m_method_is_virtual(method) && mono_method_get_imt_slot (method) != slot_num) { vt_slot ++; continue; }