diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog index 219e41236db0c..a8e31c404ec3f 100644 --- a/mono/metadata/ChangeLog +++ b/mono/metadata/ChangeLog @@ -1,3 +1,10 @@ +2007-08-20 Jb Evain + + * class-internals: add definitions for MONO_EXCEPTION_METHOD_ACCESS + and MONO_EXCEPTION_FIELD_ACCESS. + + * debug-helpers.[c|h]: new mono_field_full_name function. + 2007-08-20 Mark Probst * class.c: Removed class_security_level() and moved it to diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index baef91103572f..0babe799ecb8a 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -172,7 +172,9 @@ enum { MONO_EXCEPTION_MISSING_METHOD = 5, MONO_EXCEPTION_MISSING_FIELD = 6, MONO_EXCEPTION_TYPE_LOAD = 7, - MONO_EXCEPTION_FILE_NOT_FOUND = 8 + MONO_EXCEPTION_FILE_NOT_FOUND = 8, + MONO_EXCEPTION_METHOD_ACCESS = 9, + MONO_EXCEPTION_FIELD_ACCESS = 10, /* add other exception type */ }; diff --git a/mono/metadata/debug-helpers.c b/mono/metadata/debug-helpers.c index 337dc182b4832..3a79e24fae8c7 100644 --- a/mono/metadata/debug-helpers.c +++ b/mono/metadata/debug-helpers.c @@ -557,6 +557,18 @@ mono_disasm_code (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const return result; } +char * +mono_field_full_name (MonoClassField *field) +{ + char *res; + const char *nspace = field->parent->name_space; + + res = g_strdup_printf ("%s%s%s:%s", nspace, *nspace ? "." : "", + field->parent->name, field->name); + + return res; +} + char * mono_method_full_name (MonoMethod *method, gboolean signature) { diff --git a/mono/metadata/debug-helpers.h b/mono/metadata/debug-helpers.h index ee6924fb6823f..c63fa058409af 100644 --- a/mono/metadata/debug-helpers.h +++ b/mono/metadata/debug-helpers.h @@ -40,6 +40,8 @@ MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImag char* mono_method_full_name (MonoMethod *method, gboolean signature); +char* mono_field_full_name (MonoClassField *field); + G_END_DECLS #endif /* __MONO_DEBUG_HELPERS_H__ */ diff --git a/mono/mini/ChangeLog b/mono/mini/ChangeLog index 052be80fe0e0c..15147ad3f22ee 100644 --- a/mono/mini/ChangeLog +++ b/mono/mini/ChangeLog @@ -1,3 +1,8 @@ +2007-08-20 Jb Evain + + * mini.c (mono_method_to_ir): throw MethodAccessException + and FieldAccessException instead of InvalidProgramException. + 2007-08-20 Mark Probst * mini.c: CoreCLR security checks. diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 2abae219a37ed..973abaad4d422 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -88,6 +88,24 @@ if (cfg->exception_type != MONO_EXCEPTION_NONE)\ goto exception_exit;\ } while (0) +#define METHOD_ACCESS_FAILURE do { \ + char *method_fname = mono_method_full_name (method, TRUE); \ + char *cil_method_fname = mono_method_full_name (cil_method, TRUE); \ + cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS; \ + cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname); \ + g_free (method_fname); \ + g_free (cil_method_fname); \ + goto exception_exit; \ + } while (0) +#define FIELD_ACCESS_FAILURE do { \ + char *method_fname = mono_method_full_name (method, TRUE); \ + char *field_fname = mono_field_full_name (field); \ + cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS; \ + cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname); \ + g_free (method_fname); \ + g_free (field_fname); \ + goto exception_exit; \ + } while (0) /* * this is used to determine when some branch optimizations are possible: we exclude FP compares @@ -4653,7 +4671,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (!cmethod) goto load_error; if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cil_method)) - UNVERIFIED; + METHOD_ACCESS_FAILURE; if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip); @@ -6062,7 +6080,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b goto load_error; mono_class_init (klass); if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field)) - UNVERIFIED; + FIELD_ACCESS_FAILURE; foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset; /* FIXME: mark instructions for use in SSA */ @@ -6239,6 +6257,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (!field) goto load_error; mono_class_init (klass); + if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field)) + FIELD_ACCESS_FAILURE; g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)); @@ -10865,6 +10885,18 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in mono_raise_exception (ex); break; } + case MONO_EXCEPTION_METHOD_ACCESS: { + MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message); + mono_destroy_compile (cfg); + mono_raise_exception (ex); + break; + } + case MONO_EXCEPTION_FIELD_ACCESS: { + MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message); + mono_destroy_compile (cfg); + mono_raise_exception (ex); + break; + } /* this can only be set if the security manager is active */ case MONO_EXCEPTION_SECURITY_LINKDEMAND: { MonoAssembly *assembly = mono_image_get_assembly (method->klass->image); diff --git a/mono/tests/ChangeLog b/mono/tests/ChangeLog index ca243a8316a32..393b5990cd240 100644 --- a/mono/tests/ChangeLog +++ b/mono/tests/ChangeLog @@ -1,3 +1,8 @@ +2007-08-20 Jb Evain + + * field-access.il, method-access.il, Makefile.am: tests + for FieldAccessException and MethodAccessException. + 2007-08-16 Rodrigo Kumpera * ldtoken_with_byref_typespec.2.il: Test for (in pseudo c#) "typeof (int&)" expression diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index 1776569792f06..2c5ca0aeab9e0 100644 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -253,6 +253,8 @@ TEST_CSC_SRC= \ vararg.cs TEST_IL_SRC= \ + field-access.il \ + method-access.il \ cpblkTest.il \ vbinterface.il \ jmpTest.il \ diff --git a/mono/tests/field-access.il b/mono/tests/field-access.il new file mode 100644 index 0000000000000..929303995c4e0 --- /dev/null +++ b/mono/tests/field-access.il @@ -0,0 +1,79 @@ +.assembly extern mscorlib {} + +.assembly 'field-access' {} + +.class public FieldFail extends [mscorlib]System.Object { + + .field private static string _sfield + + .field private string _field + + .method public specialname rtspecialname instance void .ctor() + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} + +.class Test { + + .method static void read_sfield () + { + ldsfld string FieldFail::_sfield + pop + ret + } + + .method static void read_field () + { + .locals (FieldFail ff) + + newobj instance void FieldFail::.ctor() + stloc ff + ldloc ff + ldfld string FieldFail::_field + pop + ret + } + + .method static int32 Main () + { + .entrypoint + + .try { + call void Test::read_sfield () + br fail + } catch [mscorlib]System.FieldAccessException { + pop + br continue + } catch [mscorlib]System.Exception { + pop + br fail + } + +continue: + .try { + call void Test::read_field () + br fail + } catch [mscorlib]System.FieldAccessException { + pop + br success + } catch [mscorlib]System.Exception { + pop + br fail + } + +success: + ldstr "PASS" + call void [mscorlib]System.Console::WriteLine(string) + ldc.i4.0 + ret + +fail: + ldstr "FAIL" + call void [mscorlib]System.Console::WriteLine(string) + ldc.i4.1 + ret + } +} diff --git a/mono/tests/method-access.il b/mono/tests/method-access.il new file mode 100644 index 0000000000000..98e9f7fa7ff6b --- /dev/null +++ b/mono/tests/method-access.il @@ -0,0 +1,83 @@ +.assembly extern mscorlib {} + +.assembly 'method-access' {} + +.class public MethFail extends [mscorlib]System.Object { + + .method private void foo () + { + ret + } + + .method static private void sfoo () + { + ret + } + + .method public specialname rtspecialname instance void .ctor() + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} + +.class Test { + + .method static void call_sfoo () + { + call void MethFail::sfoo () + ret + } + + .method static void call_foo () + { + .locals (MethFail mf) + + newobj instance void MethFail::.ctor() + stloc mf + ldloc mf + call instance void MethFail::foo () + ret + } + + .method static int32 Main () + { + .entrypoint + + .try { + call void Test::call_sfoo () + br fail + } catch [mscorlib]System.MethodAccessException { + pop + br continue + } catch [mscorlib]System.Exception { + pop + br fail + } + +continue: + .try { + call void Test::call_foo () + br fail + } catch [mscorlib]System.MethodAccessException { + pop + br success + } catch [mscorlib]System.Exception { + pop + br fail + } + +success: + ldstr "PASS" + call void [mscorlib]System.Console::WriteLine(string) + ldc.i4.0 + ret + +fail: + ldstr "FAIL" + call void [mscorlib]System.Console::WriteLine(string) + ldc.i4.1 + ret + } +}