File mono-12802.diff of Package mono
diff --git a/mono/metadata/class-init.c b/mono/metadata/class-init.c
index 670446618186..802bd8d96855 100644
--- a/mono/metadata/class-init.c
+++ b/mono/metadata/class-init.c
@@ -1410,13 +1410,15 @@ print_implemented_interfaces (MonoClass *klass)
printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
g_free (name);
- for (i = 0; i < klass->interface_offsets_count; i++)
- printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
+ for (i = 0; i < klass->interface_offsets_count; i++) {
+ char *ic_name = mono_type_get_full_name (klass->interfaces_packed [i]);
+ printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i,
klass->interfaces_packed [i]->interface_id,
klass->interface_offsets_packed [i],
mono_class_get_method_count (klass->interfaces_packed [i]),
- klass->interfaces_packed [i]->name_space,
- klass->interfaces_packed [i]->name );
+ ic_name);
+ g_free (ic_name);
+ }
printf ("Interface flags: ");
for (i = 0; i <= klass->max_interface_id; i++)
if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
@@ -2675,6 +2677,55 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
}
}
+static void
+print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
+{
+ int i, icount = 0;
+
+ print_implemented_interfaces (klass);
+
+ for (i = 0; i <= klass->max_interface_id; i++)
+ if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
+ icount++;
+
+ printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
+ klass->vtable_size, icount);
+
+ for (i = 0; i < cur_slot; ++i) {
+ MonoMethod *cm;
+
+ cm = vtable [i];
+ if (cm) {
+ printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
+ mono_method_full_name (cm, TRUE));
+ } else {
+ printf (" slot assigned: %03d, <null>\n", i);
+ }
+ }
+
+
+ if (icount) {
+ printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
+ klass->name, klass->max_interface_id);
+
+ for (i = 0; i < klass->interface_count; i++) {
+ MonoClass *ic = klass->interfaces [i];
+ printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
+ mono_class_interface_offset (klass, ic),
+ count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
+ }
+
+ for (MonoClass *k = klass->parent; k ; k = k->parent) {
+ for (i = 0; i < k->interface_count; i++) {
+ MonoClass *ic = k->interfaces [i];
+ printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
+ mono_class_interface_offset (klass, ic),
+ count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
+ }
+ }
+ }
+}
+
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
@@ -2685,7 +2736,6 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
MonoClass *k, *ic;
MonoMethod **vtable = NULL;
int i, max_vtsize = 0, cur_slot = 0;
- guint32 max_iid;
GPtrArray *ifaces = NULL;
GHashTable *override_map = NULL;
GHashTable *override_class_map = NULL;
@@ -2747,7 +2797,6 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
return;
- max_iid = klass->max_interface_id;
DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
/* Optimized version for generic instances */
@@ -2784,6 +2833,9 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
klass->methods [i]->slot = gklass->methods [i]->slot;
}
+ if (mono_print_vtable)
+ print_vtable_layout_result (klass, klass->vtable, gklass->vtable_size);
+
return;
}
@@ -3152,6 +3204,10 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
g_free (type_name);
g_free (method_name);
+
+ if (mono_print_vtable)
+ print_vtable_layout_result (klass, vtable, cur_slot);
+
g_free (vtable);
return;
}
@@ -3183,50 +3239,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
}
DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
- if (mono_print_vtable) {
- int icount = 0;
-
- print_implemented_interfaces (klass);
-
- for (i = 0; i <= max_iid; i++)
- if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
- icount++;
-
- printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
- klass->vtable_size, icount);
-
- for (i = 0; i < cur_slot; ++i) {
- MonoMethod *cm;
-
- cm = vtable [i];
- if (cm) {
- printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
- mono_method_full_name (cm, TRUE));
- }
- }
-
-
- if (icount) {
- printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
- klass->name, max_iid);
-
- for (i = 0; i < klass->interface_count; i++) {
- ic = klass->interfaces [i];
- printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
- mono_class_interface_offset (klass, ic),
- count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
- }
-
- for (k = klass->parent; k ; k = k->parent) {
- for (i = 0; i < k->interface_count; i++) {
- ic = k->interfaces [i];
- printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
- mono_class_interface_offset (klass, ic),
- count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
- }
- }
- }
- }
+ if (mono_print_vtable)
+ print_vtable_layout_result (klass, vtable, cur_slot);
g_free (vtable);
@@ -3242,6 +3256,10 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
mono_error_cleanup (error);
g_free (name);
+ if (mono_print_vtable)
+ print_vtable_layout_result (klass, vtable, cur_slot);
+
+
g_free (vtable);
if (override_map)
g_hash_table_destroy (override_map);
@@ -4069,7 +4087,7 @@ mono_get_unique_iid (MonoClass *klass)
} else {
generic_id = 0;
}
- printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->name, type_name, generic_id);
+ printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
g_free (type_name);
}
#endif
diff --git a/mono/metadata/class.c b/mono/metadata/class.c
index 7a39e6197aff..e73324de4c7b 100644
--- a/mono/metadata/class.c
+++ b/mono/metadata/class.c
@@ -644,7 +644,7 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
* while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
* ->byref and ->attrs from @type are propagated to the returned type.
*/
- nt = mono_metadata_type_dup (image, inst->type_argv [num]);
+ nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
nt->byref = type->byref;
nt->attrs = type->attrs;
return nt;
@@ -667,7 +667,7 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
num, pname ? pname : "", inst->type_argv [num]->type);
return NULL;
}
- nt = mono_metadata_type_dup (image, inst->type_argv [num]);
+ nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
nt->byref = type->byref;
nt->attrs = type->attrs;
return nt;
@@ -790,7 +790,7 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
if (!inflated) {
MonoType *shared = mono_metadata_get_shared_type (type);
- if (shared) {
+ if (shared && !type->has_cmods) {
return shared;
} else {
return mono_metadata_type_dup (image, type);
diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h
index 05ceefcc4bfd..18dd66a78a77 100644
--- a/mono/metadata/metadata-internals.h
+++ b/mono/metadata/metadata-internals.h
@@ -894,6 +894,8 @@ void mono_unload_interface_ids (MonoBitSet *bitset);
MonoType *mono_metadata_type_dup (MonoImage *image, const MonoType *original);
+MonoType *mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *original, const MonoType *cmods_source);
+
MonoMethodSignature *mono_metadata_signature_dup_full (MonoImage *image,MonoMethodSignature *sig);
MonoMethodSignature *mono_metadata_signature_dup_mempool (MonoMemPool *mp, MonoMethodSignature *sig);
MonoMethodSignature *mono_metadata_signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass);
diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c
index 4a9586b79217..5fb478a6b62d 100644
--- a/mono/metadata/metadata.c
+++ b/mono/metadata/metadata.c
@@ -5698,13 +5698,28 @@ mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *s
*/
MonoType *
mono_metadata_type_dup (MonoImage *image, const MonoType *o)
+{
+ return mono_metadata_type_dup_with_cmods (image, o, o);
+}
+
+/**
+ * Works the same way as mono_metadata_type_dup but pick cmods from @cmods_source
+ */
+MonoType *
+mono_metadata_type_dup_with_cmods (MonoImage *image, const MonoType *o, const MonoType *cmods_source)
{
MonoType *r = NULL;
- size_t sizeof_o = mono_sizeof_type (o);
+ size_t sizeof_o = mono_sizeof_type (cmods_source);
r = image ? (MonoType *)mono_image_alloc0 (image, sizeof_o) : (MonoType *)g_malloc (sizeof_o);
- memcpy (r, o, sizeof_o);
+ if (cmods_source->has_cmods) {
+ g_assert (!image || image == mono_type_get_cmods (cmods_source)->image);
+ memcpy (r, cmods_source, sizeof_o);
+ }
+
+ memcpy (r, o, sizeof (MonoType));
+ r->has_cmods = cmods_source->has_cmods;
if (o->type == MONO_TYPE_PTR) {
r->data.type = mono_metadata_type_dup (image, o->data.type);
diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am
index 780acdb545f6..25ee74b34d80 100755
--- a/mono/tests/Makefile.am
+++ b/mono/tests/Makefile.am
@@ -694,7 +694,8 @@ TESTS_CS_SRC= \
nested_type_visibility.cs \
dynamic-method-churn.cs \
verbose.cs \
- generic-unmanaged-constraint.cs
+ generic-unmanaged-constraint.cs \
+ bug-10834.cs
# some tests fail to compile on mcs
if CSC_IS_ROSLYN
diff --git a/mono/tests/bug-10834.cs b/mono/tests/bug-10834.cs
new file mode 100644
index 000000000000..26b07d761196
--- /dev/null
+++ b/mono/tests/bug-10834.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Reflection;
+
+namespace Repro {
+ class Program
+ {
+ static bool Check (Type t)
+ {
+ Console.WriteLine ($"--- {t}");
+
+ var m = t.GetMethod ("M1");
+ Console.WriteLine (m);
+
+ foreach(var p in m.GetParameters ())
+ Console.WriteLine ($"{p}: {p.ParameterType} / {p.GetRequiredCustomModifiers().Length}");
+
+ Console.WriteLine ();
+ return m.GetParameters()[0].GetRequiredCustomModifiers().Length == 1;
+ }
+
+ static int Main(string[] args)
+ {
+ if (!Check (typeof (C<>)))
+ return 1;
+ if (!Check (typeof (C<S1>)))
+ return 2;
+
+ var o = new Bug ();
+ int res = o.M1 (new S1 ());
+ Console.WriteLine (res);
+ if (res != 0)
+ return 3;
+ Console.WriteLine ("All good");
+ return 0;
+ }
+ }
+ abstract class C<U>
+ {
+ public abstract int M1<T>(in T arg) where T : U, I1;
+ }
+
+ class Bug : C<S1>
+ {
+ public override int M1<T2> (in T2 arg)
+ {
+ Console.WriteLine ("C<S1>::M1");
+ arg.M3();
+ return arg.M4();
+ }
+ }
+
+ interface I1
+ {
+ void M3();
+ int M4();
+ }
+
+ public struct S1: I1
+ {
+ public int field;
+ public void M3 ()
+ {
+ Console.WriteLine ("S1:M3");
+ field = 42;
+ }
+
+ public int M4() {
+ Console.WriteLine ("S1:M4 {0}", field);
+
+ return field;
+ }
+ }
+}