Merge pull request #4045 from lambdageek/bug-47867
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Thu, 1 Dec 2016 15:33:25 +0000 (10:33 -0500)
committerGitHub <noreply@github.com>
Thu, 1 Dec 2016 15:33:25 +0000 (10:33 -0500)
[sre] Ensure generic_context is created before instantiating a TypeBuilder

mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs
mono/metadata/reflection.c
mono/metadata/sre.c

index ac3b1f149fa3d8e587cb8cf5a691fcc62eef46a5..6d056da47a33590723a552c93aeef3711b577dd9 100644 (file)
@@ -11190,5 +11190,63 @@ namespace MonoTests.System.Reflection.Emit
 
                interface IFoo {
                }
+
+               [Test]
+               public void GenericFieldInCreatedType () {
+                       /*
+                        * Regression test for #47867.
+                        * We construct the following, but only call CreateType on R.
+                        *
+                        * public class S<T> {
+                        *   public T t;
+                        * }
+                        * public class R {
+                        *   public static S<R> sr;
+                        * }
+                        */
+                       var aname = new AssemblyName ("example1");
+                       var ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
+                       var mb = ab.DefineDynamicModule (aname.Name);
+                       var tbS = mb.DefineType ("S", TypeAttributes.Public);
+                       tbS.DefineGenericParameters (new String [] { "T" });
+                       var tbR = mb.DefineType ("R", TypeAttributes.Public);
+                       tbR.DefineField ("sr", tbS.MakeGenericType(new Type[] { tbR }), FieldAttributes.Public | FieldAttributes.Static);
+
+                       Type r = tbR.CreateType ();
+
+                       Assert.IsNotNull  (r);
+               }
+
+               [Test]
+               public void GenericFieldInCreatedTypeIncompleteTypeTLE () {
+                       /*
+                        * Regression test for #47867.
+                        * We construct the following, but only call CreateType on R.
+                        * Then we try to use R.sr which is expected throw a
+                        * TLE because S hasn't been created yet.
+                        *
+                        * public class S<T> {
+                        *   public T t;
+                        * }
+                        * public class R {
+                        *   public static S<R> sr;
+                        * }
+                        */
+                       var aname = new AssemblyName ("example1");
+                       var ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
+                       var mb = ab.DefineDynamicModule (aname.Name);
+                       var tbS = mb.DefineType ("S", TypeAttributes.Public);
+                       tbS.DefineGenericParameters (new String [] { "T" });
+                       var tbR = mb.DefineType ("R", TypeAttributes.Public);
+                       tbR.DefineField ("sr", tbS.MakeGenericType(new Type[] { tbR }), FieldAttributes.Public | FieldAttributes.Static);
+
+                       Type r = tbR.CreateType ();
+
+                       Assert.IsNotNull  (r);
+
+                       // N.B.  tbS has not had CreateType called yet, so expect this to fail.
+                       Assert.Throws<TypeLoadException> (delegate { var ft = r.GetField("sr").FieldType; });
+               }
+               
        }
 }
index 28817a3311438815a1a8583fd60ae57dcc7b9452..6c856c6683f532a0d5ab4d3db5a9e9051a4b9c79 100644 (file)
@@ -501,9 +501,28 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err
                return res;
        }
 
-       /* This MonoGenericClass hack is no longer necessary. Let's leave it here until we finish with the 2-stage type-builder setup.*/
-       if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder)
-               g_assert (0);
+       if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder) {
+               /* This can happen if a TypeBuilder for a generic class K<T,U>
+                * had reflection_create_generic_class) called on it, but not
+                * ves_icall_TypeBuilder_create_runtime_class.  This can happen
+                * if the K`2 is refernced from a generic instantiation
+                * (e.g. K<int,string>) that appears as type argument
+                * (e.g. Dict<string,K<int,string>>), field (e.g. K<int,string>
+                * Foo) or method signature, parent class or any of the above
+                * in a nested class of some other TypeBuilder.  Such an
+                * occurrence caused mono_reflection_type_get_handle to be
+                * called on the sre generic instance (K<int,string>) which
+                * required the container_class for the generic class K`2 to be
+                * set up, but the remainder of class construction for K`2 has
+                * not been done. */
+               char * full_name = mono_type_get_full_name (klass);
+               /* I would have expected ReflectionTypeLoadException, but evidently .NET throws TLE in this case. */
+               mono_error_set_type_load_class (error, klass, "TypeBuilder.CreateType() not called for generic class %s", full_name);
+               g_free (full_name);
+               mono_domain_unlock (domain);
+               mono_loader_unlock ();
+               return NULL;
+       }
 
        if (mono_class_get_ref_info (klass) && !klass->wastypebuilder && !type->byref) {
                mono_domain_unlock (domain);
@@ -2245,6 +2264,8 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc
        if (mono_is_sre_type_builder (mono_object_class (type))) {
                is_dynamic = TRUE;
        } else if (mono_is_sre_generic_instance (mono_object_class (type))) {
+               /* Does this ever make sense?  what does instantiating a generic instance even mean? */
+               g_assert_not_reached ();
                MonoReflectionGenericClass *rgi = (MonoReflectionGenericClass *) type;
                MonoReflectionType *gtd = rgi->generic_type;
 
index d189c4a03172d91d46dddf26aa2586bb676e703f..041a2ba6f4859f38494cd49ea37422e4e4f3a8aa 100644 (file)
@@ -44,6 +44,8 @@ static guint32 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoR
 static gboolean ensure_runtime_vtable (MonoClass *klass, MonoError  *error);
 static void reflection_methodbuilder_from_dynamic_method (ReflectionMethodBuilder *rmb, MonoReflectionDynamicMethod *mb);
 static gboolean reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error);
+static gboolean reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error);
+
 
 static gpointer register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly);
 #endif
@@ -1547,7 +1549,21 @@ mono_reflection_type_get_handle (MonoReflectionType* ref, MonoError *error)
                                return NULL;
                        }
                }
-
+               /* Need to resolve the generic_type in order for it to create its generic context. */
+               MonoType *gtd = mono_reflection_type_get_handle (gclass->generic_type, error);
+               if (!is_ok (error)) {
+                       g_free (types);
+                       return NULL;
+               }
+               MonoClass *gtd_klass = mono_class_from_mono_type (gtd);
+               if (is_sre_type_builder (mono_object_class (gclass->generic_type))) {
+                       reflection_create_generic_class ((MonoReflectionTypeBuilder*)gclass->generic_type, error);
+                       if (!is_ok (error)) {
+                               g_free (types);
+                               return NULL;
+                       }
+               }
+               g_assert (count == 0 || mono_class_is_gtd (gtd_klass));
                res = mono_reflection_bind_generic_parameters (gclass->generic_type, count, types, error);
                g_free (types);
                g_assert (res);
@@ -2408,6 +2424,7 @@ reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error
        mono_error_init (error);
 
        reflection_setup_internal_class (tb, error);
+       return_val_if_nok (error, FALSE);
 
        klass = mono_class_from_mono_type (tb->type.type);
 
@@ -2416,6 +2433,9 @@ reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error
        if (count == 0)
                return TRUE;
 
+       if (mono_class_try_get_generic_container (klass) != NULL)
+               return TRUE; /* already setup */
+
        MonoGenericContainer *generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
 
        generic_container->owner.klass = klass;