[sre] Throw a TLE if a generic inst is used before the gtd is created.
authorAleksey Kliger <aleksey@xamarin.com>
Tue, 29 Nov 2016 15:31:08 +0000 (10:31 -0500)
committerAleksey Kliger <aleksey@xamarin.com>
Tue, 29 Nov 2016 16:40:19 +0000 (11:40 -0500)
This can happen if TypeBuilders are used to construct something like
  class S<T> {
    ...
  }
  class R {
    public S<int> SI;
  }

And then CreateType() is called for R and GetField("SI") is called on
  the result before CreateType() is called on the builder for S.

mono/metadata/reflection.c

index 3e42a8e4a6720cb305c4fa19295f137e3c2328fd..ddd3d6aefe7917cd3dfc7f0e296736bf24497e5e 100644 (file)
@@ -461,9 +461,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);