*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Rodrigo Kumpera
*/
#include <config.h>
}
static gboolean
-is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst)
+is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
{
int i;
for (i = 0; i < ginst->type_argc; ++i) {
MonoType *type = ginst->type_argv [i];
- if (!is_valid_type_in_context (ctx, type))
+
+ if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
return FALSE;
}
return TRUE;
MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
if (!gc) /*non-generic inflated method - it's part of a generic type */
return TRUE;
- if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst))
+ if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
return FALSE;
return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
MonoGenericClass *gklass = klass->generic_class;
MonoGenericInst *ginst = gklass->context.class_inst;
MonoGenericContainer *gc = gklass->container_class->generic_container;
- if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst))
+ if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
return FALSE;
return is_valid_generic_instantiation (gc, &gklass->context, ginst);
}
if (!is_valid_type_in_context (ctx, type)) {
char *str = mono_type_full_name (type);
ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
- type->type == MONO_TYPE_VAR ? "!" : "!!",
+ str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
str,
type->type == MONO_TYPE_VAR ? "class" : "method",
ctx->ip_offset),
* Verify if it's valid to perform a branch from @offset to @target.
* This should be used with br and brtrue/false.
* It returns 0 if valid, 1 for unverifiable and 2 for invalid.
- * The major diferent from other similiar functions is that branching into a
+ * The major difference from other similiar functions is that branching into a
* finally/fault block is invalid instead of just unverifiable.
*/
static int
* This should be used with binary comparison branching instruction, like beq, bge and similars.
* It returns 0 if valid, 1 for unverifiable and 2 for invalid.
*
- * The major diferences from other similar functions are that most errors lead to invalid
+ * The major differences from other similar functions are that most errors lead to invalid
* code and only branching out of finally, filter or fault clauses is unverifiable.
*/
static int
return generic_icollection_class;
}
+static MonoClass*
+get_ireadonlylist_class (void)
+{
+ static MonoClass* generic_ireadonlylist_class = NULL;
+
+ if (generic_ireadonlylist_class == NULL)
+ generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
+ "System.Collections.Generic", "IReadOnlyList`1");
+ return generic_ireadonlylist_class;
+}
+
+static MonoClass*
+get_ireadonlycollection_class (void)
+{
+ static MonoClass* generic_ireadonlycollection_class = NULL;
+
+ if (generic_ireadonlycollection_class == NULL)
+ generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
+ "System.Collections.Generic", "IReadOnlyCollection`1");
+ return generic_ireadonlycollection_class;
+}
+
static MonoClass*
inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
{
{
MonoClass *iface_gtd;
+ if (target == candidate)
+ return TRUE;
+
if (mono_class_has_variant_generic_params (target)) {
if (MONO_CLASS_IS_INTERFACE (target)) {
+ if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
+ return TRUE;
+
if (candidate->rank == 1) {
if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate->element_class))
return TRUE;
return TRUE;
if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate->element_class))
return TRUE;
+ if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate->element_class))
+ return TRUE;
+ if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate->element_class))
+ return TRUE;
} else {
MonoError error;
int i;
- mono_class_setup_interfaces (candidate, &error);
- if (!mono_error_ok (&error)) {
- mono_error_cleanup (&error);
- return FALSE;
- }
+ while (candidate && candidate != mono_defaults.object_class) {
+ mono_class_setup_interfaces (candidate, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+
+ /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
+ for (i = 0; i < candidate->interface_offsets_count; ++i) {
+ MonoClass *iface = candidate->interfaces_packed [i];
+ if (mono_class_is_variant_compatible (target, iface, TRUE))
+ return TRUE;
+ }
- /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
- for (i = 0; i < candidate->interface_offsets_count; ++i) {
- MonoClass *iface = candidate->interfaces_packed [i];
- if (mono_class_is_variant_compatible (target, iface, TRUE))
- return TRUE;
+ for (i = 0; i < candidate->interface_count; ++i) {
+ MonoClass *iface = candidate->interfaces [i];
+ if (mono_class_is_variant_compatible (target, iface, TRUE))
+ return TRUE;
+ }
+ candidate = candidate->parent;
}
}
} else if (target->delegate) {
}
/*TODO verify definite assigment */
- if (check_underflow (ctx, 1)) {
- value = stack_pop(ctx);
- if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
- char *expected = mono_type_full_name (ctx->locals [arg]);
- char *found = stack_slot_full_name (value);
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
- found,
- arg,
- expected,
- ctx->ip_offset));
- g_free (expected);
- g_free (found);
- }
+ if (!check_underflow (ctx, 1))
+ return;
+
+ value = stack_pop (ctx);
+ if (ctx->locals [arg]->byref && stack_slot_is_managed_mutability_pointer (value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly managed reference when storing on a local variable at 0x%04x", ctx->ip_offset));
+
+ if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
+ char *expected = mono_type_full_name (ctx->locals [arg]);
+ char *found = stack_slot_full_name (value);
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
+ found,
+ arg,
+ expected,
+ ctx->ip_offset));
+ g_free (expected);
+ g_free (found);
}
}
ILStackDesc copy;
if (mono_method_is_constructor (method) && !method->klass->valuetype) {
- if (!mono_method_is_constructor (ctx->method))
+ if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
- if (method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor to a type diferent that this or super at 0x%04x", ctx->ip_offset));
+ if (IS_STRICT_MODE (ctx) && method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor of a type different from this or super at 0x%04x", ctx->ip_offset));
ctx->super_ctor_called = TRUE;
value = stack_pop_safe (ctx);
- if ((value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
+ if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
} else {
value = stack_pop (ctx);
merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
{
MonoError error;
- int i, j, k;
+ int i, j;
stack_init (ctx, to);
if (start) {
continue;
}
+ /*Both slots are the same boxed valuetype. Simply copy it.*/
+ if (stack_slot_is_boxed_value (old_slot) &&
+ stack_slot_is_boxed_value (new_slot) &&
+ mono_metadata_type_equal (old_type, new_type)) {
+ copy_stack_value (new_slot, old_slot);
+ continue;
+ }
+
if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
char *old_name = stack_slot_full_name (old_slot);
char *new_name = stack_slot_full_name (new_slot);
&& !mono_class_from_mono_type (new_type)->valuetype
&& !stack_slot_is_managed_pointer (old_slot)
&& !stack_slot_is_managed_pointer (new_slot)) {
-
+
+ mono_class_setup_supertypes (old_class);
+ mono_class_setup_supertypes (new_class);
+
for (j = MIN (old_class->idepth, new_class->idepth) - 1; j > 0; --j) {
if (mono_metadata_type_equal (&old_class->supertypes [j]->byval_arg, &new_class->supertypes [j]->byval_arg)) {
match_class = old_class->supertypes [j];
mono_error_cleanup (&error);
goto end_verify;
}
- for (j = 0; j < old_class->interface_count; ++j) {
- for (k = 0; k < new_class->interface_count; ++k) {
- if (mono_metadata_type_equal (&old_class->interfaces [j]->byval_arg, &new_class->interfaces [k]->byval_arg)) {
+ mono_class_setup_interfaces (new_class, &error);
+ if (!mono_error_ok (&error)) {
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot merge stacks due to a TypeLoadException %s at 0x%04x", mono_error_get_message (&error), ctx->ip_offset));
+ mono_error_cleanup (&error);
+ goto end_verify;
+ }
+
+ /* if old class is an interface that new class implements */
+ if (old_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (verifier_class_is_assignable_from (old_class, new_class)) {
+ match_class = old_class;
+ goto match_found;
+ }
+ for (j = 0; j < old_class->interface_count; ++j) {
+ if (verifier_class_is_assignable_from (old_class->interfaces [j], new_class)) {
match_class = old_class->interfaces [j];
- goto match_found;
+ goto match_found;
+ }
+ }
+ }
+
+ if (new_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (verifier_class_is_assignable_from (new_class, old_class)) {
+ match_class = new_class;
+ goto match_found;
+ }
+ for (j = 0; j < new_class->interface_count; ++j) {
+ if (verifier_class_is_assignable_from (new_class->interfaces [j], old_class)) {
+ match_class = new_class->interfaces [j];
+ goto match_found;
}
}
}
ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
break;
}
-
+ if (!mono_type_is_valid_in_context (&ctx, &clause->data.catch_class->byval_arg))
+ break;
+
init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
}
else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
}
}
+ if (!ctx.valid)
+ goto cleanup;
+
original_bb = bb = mono_basic_block_split (method, &error);
if (!mono_error_ok (&error)) {
ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
mono_verifier_is_class_full_trust (MonoClass *klass)
{
/* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
- gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
+ gboolean trusted_location = !mono_security_core_clr_enabled () ?
(klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);
if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
MonoClass *ctr = *constraints;
MonoType *constraint_type = &ctr->byval_arg;
+ if (!mono_class_can_access_class (class, ctr))
+ goto fail;
+
if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
goto fail;