[sre] register a canonical MonoReflectionMethod for a methodref token
authorAleksey Kliger <aleksey@xamarin.com>
Wed, 27 Sep 2017 18:01:47 +0000 (14:01 -0400)
committerMarek Safar <marek.safar@gmail.com>
Fri, 29 Sep 2017 09:01:31 +0000 (11:01 +0200)
In mono_image_create_token we are passed in a managed reflection object and we
need to create a token for it and optionally register it so that we can resolve
that token back to a runtime structure and managed object later.

For a MonoReflectionMethod object that refers to a method from outside the
current dynamic image, we need to generate a memberref token.  It will be the
same token for the same underlying MonoMethod*.  When we go to register the
token with mono_dynamic_image_register_token we need to pass a managed object.
Unfortunately two MonoReflectionMethod objects could refer to the same
MonoMethod* but differ in their ReflectedType, so just registering the
passed-in MonoReflectionMethod means we could assert in
mono_dynamic_image_register_token because previously we may have registered the
same method via a different ReflectedType.

So what we do is we cal mono_method_get_object_handle with NULL for the
reflected type - which corresponds to just using the DeclaringType of the given
MonoMethod*.

Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=59364

mono/metadata/sre.c

index 29632463e1cc56df34012bab698632efa57ce917..48df45db99732e672656cef36644cfca5cd8081f 100644 (file)
@@ -1180,7 +1180,21 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
                                how_collide = MONO_DYN_IMAGE_TOK_NEW;
                        }
                } else {
-                       token = mono_image_get_methodref_token (assembly, method, create_open_instance);
+                       guint32 methodref_token = mono_image_get_methodref_token (assembly, method, create_open_instance);
+                       /* We need to register a 'canonical' object.  The same
+                        * MonoMethod could have been reflected via different
+                        * classes so the MonoReflectionMethod:reftype could be
+                        * different, and the object lookup in
+                        * dynamic_image_register_token would assert assert. So
+                        * we pick the MonoReflectionMethod object that has the
+                        * reflected type as NULL (ie, take the declaring type
+                        * of the method) */
+                       MonoReflectionMethodHandle canonical_obj =
+                               mono_method_get_object_handle (MONO_HANDLE_DOMAIN (obj), method, NULL, error);
+                       if (!is_ok (error))
+                               goto leave;
+                       MONO_HANDLE_ASSIGN (register_obj, canonical_obj);
+                       token = methodref_token;
                }
                /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
        } else if (strcmp (klass->name, "MonoField") == 0) {
@@ -1192,7 +1206,15 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
                        token = MONO_TOKEN_FIELD_DEF | field_table_idx;
                        how_collide = MONO_DYN_IMAGE_TOK_NEW;
                } else {
-                       token = mono_image_get_fieldref_token (assembly, field);
+                       guint32 fieldref_token = mono_image_get_fieldref_token (assembly, field);
+                       /* Same as methodref: get a canonical object to
+                        * register with the token. */
+                       MonoReflectionFieldHandle canonical_obj =
+                               mono_field_get_object_handle (MONO_HANDLE_DOMAIN (obj), field->parent, field, error);
+                       if (!is_ok (error))
+                               goto leave;
+                       MONO_HANDLE_ASSIGN (register_obj, canonical_obj);
+                       token = fieldref_token;
                }
                /*g_print ("got token 0x%08x for %s\n", token, f->field->name);*/
        } else if (strcmp (klass->name, "MonoArrayMethod") == 0) {