From: Aleksey Kliger (λgeek) Date: Tue, 22 Oct 2019 18:07:44 +0000 (-0400) Subject: [reflection] mono_method_get_base_method on a GTD should use canonical ginst (mono... X-Git-Tag: submit/tizen/20210909.063632~10331^2~5^2~310 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3cef24a08c5567039e102321efa773aad5b3dc9b;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [reflection] mono_method_get_base_method on a GTD should use canonical ginst (mono/mono#17475) * [test] GetCustomAttributes on generic type definition * [reflection] mono_method_get_base_method on a GTD should use canonical ginst The issue is in how we pass along the generic instantiation. So there are two parts here: we start with a method on a GTD which has to decompose into the GTD and it's instantiation with its own generic parameters, and then we go up to its parent and grandparent inflating and decomposing the resulting instantiation. The instantiations keep passing the last parameter as the number of parameters shrinks so that the gparam index from the original type is now out of bounds for the parent and grandparent. If we mess up, we'll get a BadImageFormatException from the runtime Fixes https://github.com/mono/mono/issues/17278 Commit migrated from https://github.com/mono/mono/commit/fb5b2c949ddd2ab09fcddb458584a5facd9ec94e --- diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index c4a2af8..dcab927 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -6253,7 +6253,17 @@ mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError return method; klass = method->klass; - if (mono_class_is_ginst (klass)) { + if (mono_class_is_gtd (klass)) { + /* If we get a GTD like Foo`2 replace look instead at its instantiation with its own generic params: Foo`2. */ + /* In particular we want generic_inst to be initialized to so that we can inflate parent classes correctly as we go + * up the class hierarchy. */ + MonoType *ty = mono_class_gtd_get_canonical_inst (klass); + g_assert (ty->type == MONO_TYPE_GENERICINST); + MonoGenericClass *gklass = ty->data.generic_class; + generic_inst = mono_generic_class_get_context (gklass); + klass = gklass->container_class; + } else if (mono_class_is_ginst (klass)) { generic_inst = mono_class_get_context (klass); klass = mono_class_get_generic_class (klass)->container_class; } @@ -6301,6 +6311,10 @@ retry: generic_inst = parent_inst; } } else { + /* When we get here, possibly after a retry, if generic_inst is + * set, then the class is must be a gtd */ + g_assert (generic_inst == NULL || mono_class_is_gtd (klass)); + klass = m_class_get_parent (klass); if (!klass) return method; @@ -6320,6 +6334,7 @@ retry: if (generic_inst) { klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error); return_val_if_nok (error, NULL); + generic_inst = NULL; } if (klass == method->klass)