Merge pull request #5567 from kumpera/fix_59334
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 28 Sep 2017 20:50:07 +0000 (16:50 -0400)
committerGitHub <noreply@github.com>
Thu, 28 Sep 2017 20:50:07 +0000 (16:50 -0400)
[runtime] Handle RuntimeWrappedException and dynamic methods. Fixes #59334

mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs
mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs
mono/metadata/class-internals.h
mono/metadata/icall-def.h
mono/metadata/object-internals.h
mono/metadata/sre.c
mono/mini/mini-exceptions.c

index 9312f1da9fe53725d40125713af0238d09eeb27a..9c642ffa0062445fd98db4fe2ef938197a3fade6 100644 (file)
@@ -257,6 +257,9 @@ namespace System.Reflection.Emit
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private static extern void basic_init (AssemblyBuilder ab);
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               static extern void UpdateNativeCustomAttributes (AssemblyBuilder ab);
+
                /* Keep this in sync with codegen.cs in mcs */
                private const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
 
@@ -949,6 +952,12 @@ namespace System.Reflection.Emit
                                cattrs = new CustomAttributeBuilder [1];
                                cattrs [0] = customBuilder;
                        }
+
+                       /*
+                       Only update the native list of custom attributes if we're adding one that is known to change dynamic execution behavior.
+                       */
+                       if (customBuilder.Ctor != null && customBuilder.Ctor.DeclaringType == typeof (System.Runtime.CompilerServices.RuntimeCompatibilityAttribute))
+                               UpdateNativeCustomAttributes (this);
                }
 
                [ComVisible (true)]
index fcf6284a00e429177e7982527ec5d406ba9eb426..f8c898d2f00095dc76ad39d04fed5704732b807f 100644 (file)
@@ -610,6 +610,102 @@ namespace MonoTests.System.Reflection.Emit
                        invoke (444);
                }
 
+               static Func<int> EmitDelegate (DynamicMethod dm) {
+                       ILGenerator il = dm.GetILGenerator ();
+                       var ret_val = il.DeclareLocal (typeof (int));
+                       var leave_label = il.DefineLabel ();
+
+                       //ret = 1;
+                       il.Emit (OpCodes.Ldc_I4, 1);
+                       il.Emit (OpCodes.Stloc, ret_val);
+
+                       // try {
+                       il.BeginExceptionBlock ();
+                       //      throw "hello";
+                       il.Emit (OpCodes.Ldstr, "hello");
+                       il.Emit (OpCodes.Throw, typeof (string));
+                       //      ret = 2
+                       il.Emit (OpCodes.Ldc_I4, 2);
+                       il.Emit (OpCodes.Stloc, ret_val);
+                       // }
+                       il.Emit (OpCodes.Leave, leave_label);
+                       //catch (string)
+                       il.BeginCatchBlock (typeof (string));
+                       il.Emit (OpCodes.Pop);
+                       //      ret = 3
+                       il.Emit (OpCodes.Ldc_I4, 3);
+                       il.Emit (OpCodes.Stloc, ret_val);
+                       //}
+                       il.Emit (OpCodes.Leave, leave_label);
+                       il.EndExceptionBlock ();
+
+                       il.MarkLabel (leave_label);
+                       //return ret;
+                       il.Emit (OpCodes.Ldloc, ret_val);
+                       il.Emit (OpCodes.Ret);
+
+                       var dele = (Func<int>)dm.CreateDelegate (typeof (Func<int>));
+                       return dele;
+               }
+
+               [Test] //see bxc #59334
+               public void ExceptionWrapping ()
+               {
+                       AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("ehatevfheiw"), AssemblyBuilderAccess.Run);
+                       AssemblyBuilder ab2 = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("ddf4234"), AssemblyBuilderAccess.Run);
+                       CustomAttributeBuilder cab = new CustomAttributeBuilder (
+                                       typeof (RuntimeCompatibilityAttribute).GetConstructor (new Type [0]),
+                                       new object [0],
+                                       new PropertyInfo[] { typeof (RuntimeCompatibilityAttribute).GetProperty ("WrapNonExceptionThrows") },
+                                       new object[] { true });
+                       ab2.SetCustomAttribute (cab);
+
+                       AssemblyBuilder ab3 = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("frfhfher"), AssemblyBuilderAccess.Run);
+                       //1 NamedArg. Property name: WrapNonExceptionThrows value: true (0x01) 
+                       byte[] blob = new byte[] { 0x01, 0x00, 0x01, 0x00, 0x54, 0x02, 0x16, 0x57, 0x72, 0x61, 0x70, 0x4E, 0x6F, 0x6E, 0x45, 0x78,
+                               0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x68, 0x72, 0x6F, 0x77, 0x73, 0x01 };
+                       ab3.SetCustomAttribute (typeof (RuntimeCompatibilityAttribute).GetConstructor (new Type [0]), blob);
+               
+                       DynamicMethod invoke_no_module = new DynamicMethod("throw_1", typeof (int), new Type [0]);
+                       DynamicMethod invoke_with_module = new DynamicMethod("throw_2", typeof (int), new Type [0], typeof (DynamicMethodTest).Module);
+                       DynamicMethod invoke_with_ab = new DynamicMethod("throw_3", typeof (int), new Type [0], ab.ManifestModule);
+                       DynamicMethod invoke_with_ab2 = new DynamicMethod("throw_4", typeof (int), new Type [0], ab2.ManifestModule);
+                       DynamicMethod invoke_with_ab3 = new DynamicMethod("throw_5", typeof (int), new Type [0], ab3.ManifestModule);
+
+                       int result = 0;
+                       try {
+                               int res = EmitDelegate (invoke_no_module)();
+                               Assert.AreEqual (3, res, "invoke_no_module bad return value");
+                       } catch (RuntimeWrappedException e) {
+                               Assert.Fail ("invoke_no_module threw RWE");
+                       }
+
+                       try {
+                               int res = EmitDelegate (invoke_with_module)();
+                               Assert.Fail ("invoke_with_module did not throw RWE");
+                       } catch (RuntimeWrappedException e) {
+                       }
+
+                       try {
+                               int res = EmitDelegate (invoke_with_ab)();
+                               Assert.AreEqual (3, res, "invoke_with_ab bad return value");
+                       } catch (RuntimeWrappedException e) {
+                               Assert.Fail ("invoke_with_ab threw RWE");
+                       }
+
+                       try {
+                               int res = EmitDelegate (invoke_with_ab2)();
+                               Assert.Fail ("invoke_with_ab2 did not throw RWE");
+                       } catch (RuntimeWrappedException e) {
+                       }
+
+                       try {
+                               int res = EmitDelegate (invoke_with_ab3)();
+                               Assert.Fail ("invoke_with_a3 did not throw RWE");
+                       } catch (RuntimeWrappedException e) {
+                       }                       
+               }
+
 #if !MONODROID
                // RUNTIME: crash
                [Test]
index f744fc1fdc4c66144ab648e52b7f9f0160953c40..e3d9e18741752ec88e7136cda18776ea7d25c736 100644 (file)
@@ -27,6 +27,7 @@ extern gboolean mono_align_small_structs;
 typedef struct _MonoMethodWrapper MonoMethodWrapper;
 typedef struct _MonoMethodInflated MonoMethodInflated;
 typedef struct _MonoMethodPInvoke MonoMethodPInvoke;
+typedef struct _MonoDynamicMethod MonoDynamicMethod;
 
 /* Properties that applies to a group of structs should better use a higher number
  * to avoid colision with type specific properties.
@@ -100,6 +101,11 @@ struct _MonoMethodWrapper {
        void *method_data;
 };
 
+struct _MonoDynamicMethod {
+       MonoMethodWrapper method;
+       MonoAssembly *assembly;
+};
+
 struct _MonoMethodPInvoke {
        MonoMethod method;
        gpointer addr;
index 28615d8c1a986bb9eacb71051805387e20e365f0..47fbefe2cda02b7ebb2a3794a02be0e393c5e3ae 100644 (file)
@@ -535,7 +535,8 @@ ICALL(ASSEMN_2, "get_public_token", mono_digest_get_public_token)
 ICALL_TYPE(CATTR_DATA, "System.Reflection.CustomAttributeData", CATTR_DATA_1)
 ICALL(CATTR_DATA_1, "ResolveArgumentsInternal", ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal)
 
-ICALL_TYPE(ASSEMB, "System.Reflection.Emit.AssemblyBuilder", ASSEMB_2)
+ICALL_TYPE(ASSEMB, "System.Reflection.Emit.AssemblyBuilder", ASSEMB_1)
+HANDLES(ICALL(ASSEMB_1, "UpdateNativeCustomAttributes", ves_icall_AssemblyBuilder_UpdateNativeCustomAttributes))
 ICALL(ASSEMB_2, "basic_init", ves_icall_AssemblyBuilder_basic_init)
 
 #ifndef DISABLE_REFLECTION_EMIT
index 3b4db614bba06297be0e6e70e2a96e35f4e9a21a..26b11d77371cea4845516ba3b19805a7f4390335 100644 (file)
@@ -1926,8 +1926,8 @@ ves_icall_ModuleBuilder_GetRegisteredToken (MonoReflectionModuleBuilderHandle mb
 void
 ves_icall_AssemblyBuilder_basic_init (MonoReflectionAssemblyBuilder *assemblyb);
 
-MonoReflectionModule*
-ves_icall_AssemblyBuilder_InternalAddModule (MonoReflectionAssemblyBuilder *ab, MonoString *fileName);
+void
+ves_icall_AssemblyBuilder_UpdateNativeCustomAttributes (MonoReflectionAssemblyBuilderHandle assemblyb, MonoError *error);
 
 MonoArray*
 ves_icall_CustomAttributeBuilder_GetBlob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues);
index 649791e7beafcb4104a181e0c720a2509ea53d4b..3bcba2bf0cf75267ab34d01c3f47a62cd6bf50cc 100644 (file)
@@ -374,6 +374,12 @@ mono_save_custom_attrs (MonoImage *image, void *obj, MonoArray *cattrs)
        mono_image_property_insert (image, obj, MONO_PROP_DYNAMIC_CATTR, ainfo);
        mono_loader_unlock ();
 
+}
+#else
+//FIXME some code compiled under DISABLE_REFLECTION_EMIT depends on this function, we should be more aggressively disabling things
+static void
+mono_save_custom_attrs (MonoImage *image, void *obj, MonoArray *cattrs)
+{
 }
 #endif
 
@@ -2777,7 +2783,7 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass,
                        (rmb->iattrs & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
                m = (MonoMethod *)image_g_new0 (image, MonoMethodPInvoke, 1);
        else
-               m = (MonoMethod *)image_g_new0 (image, MonoMethodWrapper, 1);
+               m = (MonoMethod *)image_g_new0 (image, MonoDynamicMethod, 1);
 
        wrapperm = (MonoMethodWrapper*)m;
 
@@ -2872,6 +2878,8 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass,
                }
 
                wrapperm->header = header;
+               MonoDynamicMethod *dm = (MonoDynamicMethod*)wrapperm;
+               dm->assembly = klass->image->assembly;
        }
 
        if (rmb->generic_params) {
@@ -3908,6 +3916,7 @@ reflection_create_dynamic_method (MonoReflectionDynamicMethodHandle ref_mb, Mono
                rmb.refs [i + 1] = handle_class;
        }               
 
+       MonoAssembly *ass = NULL;
        if (mb->owner) {
                MonoType *owner_type = mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner, error);
                if (!is_ok (error)) {
@@ -3915,11 +3924,14 @@ reflection_create_dynamic_method (MonoReflectionDynamicMethodHandle ref_mb, Mono
                        return FALSE;
                }
                klass = mono_class_from_mono_type (owner_type);
+               ass = klass->image->assembly;
        } else {
                klass = mono_defaults.object_class;
+               ass = (mb->module && mb->module->image) ? mb->module->image->assembly : NULL;
        }
 
        mb->mhandle = handle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig, error);
+       ((MonoDynamicMethod*)handle)->assembly = ass;
        g_free (rmb.refs);
        return_val_if_nok (error, FALSE);
 
@@ -4371,6 +4383,18 @@ ves_icall_AssemblyBuilder_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
        mono_reflection_dynimage_basic_init (assemblyb);
 }
 
+void
+ves_icall_AssemblyBuilder_UpdateNativeCustomAttributes (MonoReflectionAssemblyBuilderHandle assemblyb, MonoError *error)
+{
+       MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
+
+       MonoReflectionAssemblyHandle assembly_handle = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
+       MonoAssembly *assembly = MONO_HANDLE_GETVAL (assembly_handle, assembly);
+       g_assert (assembly);
+
+       mono_save_custom_attrs (assembly->image, assembly, MONO_HANDLE_RAW (cattrs));
+}
+
 void
 ves_icall_EnumBuilder_setup_enum_type (MonoReflectionTypeHandle enumtype,
                                       MonoReflectionTypeHandle t,
index 10cf1b75cb194d9051761962546b5ffba8b9f8f8..e3461a80aec1631eb756b7d15f18d5133125ede3 100644 (file)
@@ -1415,6 +1415,11 @@ wrap_non_exception_throws (MonoMethod *m)
        int i;
        gboolean val = FALSE;
 
+       if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+               MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
+               if (dm->assembly)
+                       ass = dm->assembly;
+       }
        g_assert (ass);
        if (ass->wrap_non_exception_throws_inited)
                return ass->wrap_non_exception_throws;