From: Aleksey Kliger (λgeek) Date: Thu, 1 Dec 2016 15:33:25 +0000 (-0500) Subject: Merge pull request #4045 from lambdageek/bug-47867 X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=a713a14521da8ddf992c4a3e64855d56cb7897a3;hp=0e1a4d8a68024e4f77f9d415de5734140d77b824;p=mono.git Merge pull request #4045 from lambdageek/bug-47867 [sre] Ensure generic_context is created before instantiating a TypeBuilder --- diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs index ac3b1f149fa..6d056da47a3 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs @@ -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 { + * public T t; + * } + * public class R { + * public static S 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 { + * public T t; + * } + * public class R { + * public static S 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 (delegate { var ft = r.GetField("sr").FieldType; }); + } + } } diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index 28817a33114..6c856c6683f 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -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 + * 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) that appears as type argument + * (e.g. Dict>), field (e.g. K + * 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) 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; diff --git a/mono/metadata/sre.c b/mono/metadata/sre.c index d189c4a0317..041a2ba6f48 100644 --- a/mono/metadata/sre.c +++ b/mono/metadata/sre.c @@ -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;