Hey,

The attached patch changes class.c/inflate_generic_type to not abort the
runtime when facing a bad instantiation.

My only issue is that I'm not sure if mono_class_inflate_generic_type* and
mono_class_inflate_generic_class should
set a loader error when returning null. I don't think this is necessary as
this is something their callers should do. But maybe
mono_class_inflate_generic_method_full should.

This patch doesn't fix the whole thing as an audit of all callers of
mono_class_inflate_generic_type(_with_mempool | _no_copy)
and mono_class_inflate_generic_class are required to property handle them
returning NULL.

I got some local tests for these errors, but they are not in good shape for
been part of this patch.

Please review,
Rodrigo
diff --git a/mono/metadata/class.c b/mono/metadata/class.c
index 1924290..e702ef2 100644
--- a/mono/metadata/class.c
+++ b/mono/metadata/class.c
@@ -490,20 +490,24 @@ mono_class_is_open_constructed_type (MonoType *t)
 	}
 }
 
-static MonoType*
-inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context)
+/*
+ * This function returns TRUE if it could proper inflate @type.
+ * The resulting type can be found in @res  
+ */
+static gboolean
+inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoType **res)
 {
+#define SUCCESS(VAL) do { *res = VAL; return TRUE; } while (0)
+#define ERROR() do { *res = NULL; return FALSE; } while (0)
 	switch (type->type) {
 	case MONO_TYPE_MVAR: {
 		MonoType *nt;
 		int num = mono_type_get_generic_param_num (type);
 		MonoGenericInst *inst = context->method_inst;
 		if (!inst || !inst->type_argv)
-			return NULL;
+			SUCCESS (NULL);
 		if (num >= inst->type_argc)
-			g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations",
-				num, mono_generic_param_info (type->data.generic_param)->name, inst->type_argc);
-
+			ERROR ();
 		/*
 		 * Note that the VAR/MVAR cases are different from the rest.  The other cases duplicate @type,
 		 * while the VAR/MVAR duplicates a type from the context.  So, we need to ensure that the
@@ -512,60 +516,63 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
 		nt = mono_metadata_type_dup (image, inst->type_argv [num]);
 		nt->byref = type->byref;
 		nt->attrs = type->attrs;
-		return nt;
+		SUCCESS (nt);
 	}
 	case MONO_TYPE_VAR: {
 		MonoType *nt;
 		int num = mono_type_get_generic_param_num (type);
 		MonoGenericInst *inst = context->class_inst;
 		if (!inst)
-			return NULL;
+			SUCCESS (NULL);
 		if (num >= inst->type_argc)
-			g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations",
-				num, mono_generic_param_info (type->data.generic_param)->name, inst->type_argc);
+			ERROR ();
 		nt = mono_metadata_type_dup (image, inst->type_argv [num]);
 		nt->byref = type->byref;
 		nt->attrs = type->attrs;
-		return nt;
+		SUCCESS (nt);
 	}
 	case MONO_TYPE_SZARRAY: {
 		MonoClass *eclass = type->data.klass;
-		MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
+		MonoType *nt, *inflated;
+		if (!inflate_generic_type (NULL, &eclass->byval_arg, context, &inflated))
+			ERROR ();
 		if (!inflated)
-			return NULL;
+			SUCCESS (NULL);
 		nt = mono_metadata_type_dup (image, type);
 		nt->data.klass = mono_class_from_mono_type (inflated);
 		mono_metadata_free_type (inflated);
-		return nt;
+		SUCCESS (nt);
 	}
 	case MONO_TYPE_ARRAY: {
 		MonoClass *eclass = type->data.array->eklass;
-		MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
+		MonoType *nt, *inflated;
+		if (!inflate_generic_type (NULL, &eclass->byval_arg, context, &inflated))
+			ERROR ();
 		if (!inflated)
-			return NULL;
+			SUCCESS (NULL);
 		nt = mono_metadata_type_dup (image, type);
 		nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType));
 		nt->data.array->eklass = mono_class_from_mono_type (inflated);
 		mono_metadata_free_type (inflated);
-		return nt;
+		SUCCESS (nt);
 	}
 	case MONO_TYPE_GENERICINST: {
 		MonoGenericClass *gclass = type->data.generic_class;
 		MonoGenericInst *inst;
 		MonoType *nt;
 		if (!gclass->context.class_inst->is_open)
-			return NULL;
+			SUCCESS (NULL);
 
 		inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context);
 		if (inst != gclass->context.class_inst)
 			gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
 
 		if (gclass == type->data.generic_class)
-			return NULL;
+			SUCCESS (NULL);
 
 		nt = mono_metadata_type_dup (image, type);
 		nt->data.generic_class = gclass;
-		return nt;
+		SUCCESS (nt);
 	}
 	case MONO_TYPE_CLASS:
 	case MONO_TYPE_VALUETYPE: {
@@ -576,24 +583,26 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
 		MonoType *nt;
 
 		if (!container)
-			return NULL;
+			SUCCESS (NULL);
 
 		/* We can't use context->class_inst directly, since it can have more elements */
 		inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context);
 		if (inst == container->context.class_inst)
-			return NULL;
+			SUCCESS (NULL);
 
 		gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
 
 		nt = mono_metadata_type_dup (image, type);
 		nt->type = MONO_TYPE_GENERICINST;
 		nt->data.generic_class = gclass;
-		return nt;
+		SUCCESS (nt);
 	}
 	default:
-		return NULL;
+		SUCCESS (NULL);
 	}
-	return NULL;
+	SUCCESS (NULL);
+#undef SUCCESS
+#undef ERROR
 }
 
 MonoGenericContext *
@@ -645,14 +654,18 @@ mono_class_get_generic_class (MonoClass *klass)
  * allocated on the heap and is owned by the caller.
  * The returned type can potentially be the same as TYPE, so it should not be
  * modified by the caller, and it should be freed using mono_metadata_free_type ().
+ * 
+ * Returns: The inflated type or NULL on error.
  */
 MonoType*
 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context)
 {
 	MonoType *inflated = NULL; 
 
-	if (context)
-		inflated = inflate_generic_type (image, type, context);
+	if (context) {
+		if (!inflate_generic_type (image, type, context, &inflated))
+			return NULL;
+	}
 
 	if (!inflated) {
 		MonoType *shared = mono_metadata_get_shared_type (type);
@@ -677,7 +690,7 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
  * generics context @context.
  *
  * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
- * on the heap and is owned by the caller.
+ * on the heap and is owned by the caller. The result will be NULL on error.
  */
 MonoType*
 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
@@ -690,14 +703,18 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
  *
  *   Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
  * was done.
+ * 
+ * Returns: The inflated type or NULL on error.
  */
 static MonoType*
 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context)
 {
 	MonoType *inflated = NULL; 
 
-	if (context)
-		inflated = inflate_generic_type (image, type, context);
+	if (context) {
+		if (!inflate_generic_type (image, type, context, &inflated))
+			return NULL;
+	}
 
 	if (!inflated)
 		return type;
@@ -710,6 +727,9 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
  * mono_class_inflate_generic_class:
  *
  *   Inflate the class GKLASS with CONTEXT.
+ *
+ * Returns: The inflated class or NULL on error.
+ * 
  */
 MonoClass*
 mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
@@ -718,6 +738,8 @@ mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context
 	MonoType *inflated;
 
 	inflated = mono_class_inflate_generic_type (&gklass->byval_arg, context);
+	if (!inflated)
+		return NULL;
 
 	res = mono_class_from_mono_type (inflated);
 	mono_metadata_free_type (inflated);
@@ -765,6 +787,8 @@ mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *conte
  * Instantiate method @method with the generic context @context.
  * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
  *         Use mono_method_signature () and mono_method_get_header () to get the correct values.
+ *
+ * Returns: The inflated method or NULL on error. 
  */
 MonoMethod*
 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
@@ -887,7 +911,11 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
 		result->klass = klass_hint;
 
 	if (!result->klass) {
-		MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context);
+		MonoType *inflated;
+		if (!inflate_generic_type (NULL, &method->klass->byval_arg, context, &inflated)) {
+			g_free (iresult);
+			return NULL;
+		}
 		result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
 		if (inflated)
 			mono_metadata_free_type (inflated);
@@ -1039,6 +1067,8 @@ mono_class_find_enum_basetype (MonoClass *class)
 		if (class->generic_class) {
 			//FIXME do we leak here?
 			ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
+			if (!ftype)
+				return NULL;
 			ftype->attrs = cols [MONO_FIELD_FLAGS];
 		}
 
@@ -1173,6 +1203,10 @@ mono_class_setup_fields (MonoClass *class)
 			field->name = mono_field_get_name (gfield);
 			/*This memory must come from the image mempool as we don't have a chance to free it.*/
 			field->type = mono_class_inflate_generic_type_no_copy (class->image, gfield->type, mono_class_get_context (class));
+			if (!field->type) {
+				mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+				break;
+			}
 			g_assert (field->type->attrs == gfield->type->attrs);
 			if (mono_field_is_deleted (field))
 				continue;
@@ -4836,6 +4870,8 @@ mono_class_from_mono_type (MonoType *type)
  * @image: context where the image is created
  * @type_spec:  typespec token
  * @context: the generic context used to evaluate generic instantiations in
+ * 
+ * Returns: The type from the typespec or NULL on error.
  */
 static MonoType *
 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
@@ -4844,7 +4880,9 @@ mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGener
 	if (!t)
 		return NULL;
 	if (context && (context->class_inst || context->method_inst)) {
-		MonoType *inflated = inflate_generic_type (NULL, t, context);
+		MonoType *inflated;
+		if (!inflate_generic_type (NULL, t, context, &inflated))
+			return NULL;
 		if (inflated) {
 			t = inflated;
 			*did_inflate = TRUE;
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to