}
}
+static gboolean
+is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
+ {
+ do {
+ if (outer_klass == inner_klass)
+ return TRUE;
+ inner_klass = inner_klass->nested_in;
+ } while (inner_klass);
+ return FALSE;
+}
+
+/*
+ * Subtype can only access parent members with family protection if the site object
+ * is subclass of Subtype. For example:
+ * class A { protected int x; }
+ * class B : A {
+ * void valid_access () {
+ * B b;
+ * b.x = 0;
+ * }
+ * void invalid_access () {
+ * A a;
+ * a.x = 0;
+ * }
+ * }
+ * */
+static gboolean
+is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
+{
+ if (!mono_class_has_parent (access_klass, member_klass))
+ return FALSE;
+
+ if (context_klass == NULL)
+ return TRUE;
+ /*if access_klass is not member_klass context_klass must be type compat*/
+ if (access_klass != member_klass && !mono_class_has_parent (context_klass, access_klass))
+ return FALSE;
+ return TRUE;
+}
+
static gboolean
can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
{
return NULL;
}
+static gboolean
+can_access_type (MonoClass *access_klass, MonoClass *member_klass)
+{
+ int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+ if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
+ return TRUE;
+
+ if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
+ return FALSE;
+
+ switch (access_level) {
+ case TYPE_ATTRIBUTE_NOT_PUBLIC:
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+ case TYPE_ATTRIBUTE_PUBLIC:
+ return TRUE;
+
+ case TYPE_ATTRIBUTE_NESTED_PUBLIC:
+ return TRUE;
+
+ case TYPE_ATTRIBUTE_NESTED_PRIVATE:
+ return is_nesting_type (member_klass, access_klass);
+
+ case TYPE_ATTRIBUTE_NESTED_FAMILY:
+ return mono_class_has_parent (access_klass, member_klass->nested_in);
+
+ case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+ case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
+ return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
+ mono_class_has_parent (access_klass, member_klass->nested_in);
+
+ case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
+ return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
+ mono_class_has_parent (access_klass, member_klass->nested_in);
+ }
+ return FALSE;
+}
+
/* FIXME: check visibility of type, too */
static gboolean
-can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
{
MonoClass *member_generic_def;
if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
else
access_container = access_klass->generic_class->container_class;
- if (can_access_member (access_container, member_generic_def, access_level))
+ if (can_access_member (access_container, member_generic_def, context_klass, access_level))
return TRUE;
}
case FIELD_ATTRIBUTE_PRIVATE:
return access_klass == member_klass;
case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
- if (mono_class_has_parent (access_klass, member_klass) &&
+ if (is_valid_family_access (access_klass, member_klass, context_klass) &&
can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
return TRUE;
return FALSE;
case FIELD_ATTRIBUTE_ASSEMBLY:
return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
case FIELD_ATTRIBUTE_FAMILY:
- if (mono_class_has_parent (access_klass, member_klass))
+ if (is_valid_family_access (access_klass, member_klass, context_klass))
return TRUE;
return FALSE;
case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
- if (mono_class_has_parent (access_klass, member_klass))
+ if (is_valid_family_access (access_klass, member_klass, context_klass))
return TRUE;
return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
case FIELD_ATTRIBUTE_PUBLIC:
mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
{
/* FIXME: check all overlapping fields */
- int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ int can = can_access_member (method->klass, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
if (!can) {
MonoClass *nested = method->klass->nested_in;
while (nested) {
- can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ can = can_access_member (nested, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
if (can)
return TRUE;
nested = nested->nested_in;
gboolean
mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
{
- int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
if (!can) {
MonoClass *nested = method->klass->nested_in;
while (nested) {
- can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
if (can)
return TRUE;
nested = nested->nested_in;
return can;
}
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method
+ * @called: The called method
+ * @context_klass:TThe static type on stack of the owner @called object used
+ *
+ * This function must be used with instance calls, as they have more strict family accessibility.
+ * It can be used with static mehthod, but context_klass should be NULL.
+ *
+ * Returns: TRUE if caller have proper visibility and acessibility to @called
+ */
+gboolean
+mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
+{
+ MonoClass *access_class = method->klass;
+ MonoClass *member_class = called->klass;
+ int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = access_class->nested_in;
+ while (nested) {
+ can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (can)
+ return TRUE;
+ nested = nested->nested_in;
+ }
+ }
+
+ if (!can)
+ return FALSE;
+
+ if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method
+ * @field: The accessed field
+ * @context_klass: The static type on stack of the owner @field object used
+ *
+ * This function must be used with instance fields, as they have more strict family accessibility.
+ * It can be used with static fields, but context_klass should be NULL.
+ *
+ * Returns: TRUE if caller have proper visibility and acessibility to @field
+ */
+gboolean
+mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
+{
+ MonoClass *access_class = method->klass;
+ MonoClass *member_class = field->parent;
+ /* FIXME: check all overlapping fields */
+ int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = access_class->nested_in;
+ while (nested) {
+ can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (can)
+ return TRUE;
+ nested = nested->nested_in;
+ }
+ }
+
+ if (!can)
+ return FALSE;
+
+ if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+ return FALSE;
+ return TRUE;
+}
+
/**
* mono_type_is_valid_enum_basetype:
* @type: The MonoType to check
}
if (!verify_stack_type_compatibility (ctx, type, ©))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature at 0x%04x", ctx->ip_offset));
- }
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method (ctx->method, method))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, value->type->data.klass))
+ CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
+
+ } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
if (sig->ret->type != MONO_TYPE_VOID) {
!(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
return;
}
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
if (!verify_stack_type_compatibility (ctx, field->type, value))
MonoClass *klass;
/*must be one of: complex type, managed pointer (to complex type), unmanaged pointer (native int) or an instance of a value type */
- if (!( stack_slot_get_underlying_type (obj) == TYPE_COMPLEX
+ if (!(stack_slot_get_underlying_type (obj) == TYPE_COMPLEX
|| stack_slot_get_type (obj) == TYPE_NATIVE_INT
|| stack_slot_get_type (obj) == TYPE_PTR)) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument %s to load field at 0x%04x", stack_slot_get_name (obj), ctx->ip_offset));
if (!stack_slot_is_null_literal (obj) && !verify_type_compatibility (ctx, &field->parent->byval_arg, mono_type_get_type_byval (obj->type)))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, obj->type->data.klass))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
- }
-
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
- if (!mono_method_can_access_method (ctx->method, method))
+ if (!mono_method_can_access_method_full (ctx->method, method, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Constructor not visible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
//FIXME use mono_method_get_signature_full
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
}
- if (!mono_method_can_access_method (ctx->method, method))
+ if (!mono_method_can_access_method_full (ctx->method, method, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Loaded method is not visible for ldftn/ldvirtftn at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));