Skip to content

Commit 49be953

Browse files
committed
Don't return null target methods in GetInterfaceMap for abstract classes, or classes using DIMs (mono#21112)
* Don't return null target methods in GetInterfaceMap for abstract classes, or classes using DIMs If the interface method is reabstracted, and either the found implementation method is abstract, or the found implementation method is from another DIM (meaning neither klass nor any of its ancestor classes implemented the method), then say the target method is null. Otherwise return the found implementation method, even if it is abstract. Corresponding dotnet/runtime PR is dotnet/runtime#53972 Fixes dotnet/runtime#53933 * Add method flags accessors; cleanup interface map code Ported from dotnet/runtime#54271
1 parent 41c1733 commit 49be953

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

mono/metadata/class-inlines.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,29 @@ m_class_is_private (MonoClass *klass)
200200
return (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NOT_PUBLIC;
201201
}
202202

203+
static inline gboolean
204+
m_method_is_static (MonoMethod *method)
205+
{
206+
return (method->flags & METHOD_ATTRIBUTE_STATIC) != 0;
207+
}
208+
static inline gboolean
209+
m_method_is_virtual (MonoMethod *method)
210+
{
211+
return (method->flags & METHOD_ATTRIBUTE_VIRTUAL) != 0;
212+
}
213+
214+
static inline gboolean
215+
m_method_is_abstract (MonoMethod *method)
216+
{
217+
return (method->flags & METHOD_ATTRIBUTE_ABSTRACT) != 0;
218+
}
219+
220+
static inline gboolean
221+
m_method_is_final (MonoMethod *method)
222+
{
223+
return (method->flags & METHOD_ATTRIBUTE_FINAL) != 0;
224+
}
225+
203226
static inline gboolean
204227
m_method_is_icall (MonoMethod *method)
205228
{

mono/metadata/icall.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2973,6 +2973,23 @@ ves_icall_RuntimeType_GetInterfaces (MonoReflectionTypeHandle ref_type, MonoErro
29732973
return NULL_HANDLE_ARRAY;
29742974
}
29752975

2976+
static gboolean
2977+
method_is_reabstracted (MonoMethod *method)
2978+
{
2979+
/* only on interfaces */
2980+
/* method is marked "final abstract" */
2981+
/* FIXME: we need some other way to detect reabstracted methods. "final" is an incidental detail of the spec. */
2982+
return m_method_is_final (method) && m_method_is_abstract (method);
2983+
}
2984+
2985+
static gboolean
2986+
method_is_dim (MonoMethod *method)
2987+
{
2988+
/* only valid on interface methods*/
2989+
/* method is marked "virtual" but not "virtual abstract" */
2990+
return m_method_is_virtual (method) && !m_method_is_abstract (method);
2991+
}
2992+
29762993
static gboolean
29772994
set_interface_map_data_method_object (MonoDomain *domain, MonoMethod *method, MonoClass *iclass, int ioffset, MonoClass *klass, MonoArrayHandle targets, MonoArrayHandle methods, int i, MonoError *error)
29782995
{
@@ -3006,9 +3023,25 @@ set_interface_map_data_method_object (MonoDomain *domain, MonoMethod *method, Mo
30063023
}
30073024
}
30083025

3009-
if (foundMethod->flags & METHOD_ATTRIBUTE_ABSTRACT)
3026+
/*
3027+
* if the iterface method is reabstracted, and either the found implementation method is abstract, or the found
3028+
* implementation method is from another DIM (meaning neither klass nor any of its ancestor classes implemented
3029+
* the method), then say the target method is null.
3030+
*/
3031+
if (method_is_reabstracted (method) &&
3032+
(m_method_is_abstract (foundMethod) ||
3033+
(mono_class_is_interface (foundMethod->klass) && method_is_dim (foundMethod))))
30103034
MONO_HANDLE_ARRAY_SETREF (targets, i, NULL_HANDLE);
3011-
else {
3035+
else if (mono_class_is_interface (foundMethod->klass) && method_is_reabstracted (foundMethod) && !m_class_is_abstract (klass)) {
3036+
/* if the method we found is a reabstracted DIM method, but the class isn't abstract, return NULL */
3037+
/*
3038+
* (C# doesn't seem to allow constructing such types, it requires the whole class to be abstract - in
3039+
* which case we are supposed to return the reabstracted interface method. But in IL we can make a
3040+
* non-abstract class with reabstracted interface methods - which is supposed to fail with an
3041+
* EntryPointNotFoundException at invoke time, but does not prevent the class from loading.)
3042+
*/
3043+
MONO_HANDLE_ARRAY_SETREF (targets, i, NULL_HANDLE);
3044+
} else {
30123045
MONO_HANDLE_ASSIGN (member, mono_method_get_object_handle (domain, foundMethod, mono_class_is_interface (foundMethod->klass) ? foundMethod->klass : klass, error));
30133046
goto_if_nok (error, leave);
30143047
MONO_HANDLE_ARRAY_SETREF (targets, i, member);

0 commit comments

Comments
 (0)