From f7efd4a033150ea75b557becd9705b46d971fcdf Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 Oct 2020 10:30:36 -0700 Subject: [PATCH 1/3] Convert now-invalid C# in UnmanagedCallersOnly test to IL. --- .../UnmanagedCallersOnly/InvalidCallbacks.il | 92 ++++++++++++++++++- .../UnmanagedCallersOnlyTest.cs | 19 ++-- 2 files changed, 102 insertions(+), 9 deletions(-) diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il index bd391367f5233..487ad66f1a26c 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il +++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il @@ -7,7 +7,7 @@ .assembly InvalidCSharp { } .class public auto ansi beforefieldinit InvalidCSharp.GenericClass`1 - extends System.Object + extends [System.Runtime]System.Object { .method public hidebysig static void CallbackMethod ( @@ -73,3 +73,93 @@ IL_0006: ret } } + +.class public auto ansi beforefieldinit InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly + extends [System.Runtime]System.Object +{ + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: ret + } + + .method public hidebysig static + int32 ManagedDoubleCallback ( + int32 n + ) cil managed + { + .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + .maxstack 1 + .locals init ( + [0] int32 + ) + + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call int32 InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::DoubleImpl(int32) + IL_0007: stloc.0 + IL_0008: br.s IL_000a + + IL_000a: ldloc.0 + IL_000b: ret + } + + .method private hidebysig static + int32 DoubleImpl ( + int32 n + ) cil managed + { + .maxstack 2 + .locals init ( + [0] int32 + ) + + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: ldarg.0 + IL_0003: mul + IL_0004: stloc.0 + IL_0005: br.s IL_0007 + + IL_0007: ldloc.0 + IL_0008: ret + } + + .method public hidebysig static + class [System.Runtime]System.Func`2 GetDoubleDelegate () cil managed + { + .maxstack 8 + + IL_0000: ldnull + IL_0001: ldftn int32 InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::ManagedDoubleCallback(int32) + IL_0007: newobj instance void class [System.Runtime]System.Func`2::.ctor(object, native int) + IL_000c: ret + } + + .method public hidebysig static pinvokeimpl("UnmanagedCallersOnlyDll" as "DoesntExist" winapi) + int32 PInvokeMarkedWithUnmanagedCallersOnly ( + int32 n + ) cil managed preservesig + { + .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + } + + .method public hidebysig static + int32 CallPInvokeMarkedWithUnmanagedCallersOnly ( + int32 n + ) cil managed + { + .maxstack 1 + + ldarg.0 + call int32 InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::PInvokeMarkedWithUnmanagedCallersOnly(int32) + ret + } +} \ No newline at end of file diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs index 0a2b5307da315..90616cb182f29 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -29,10 +29,6 @@ public static class UnmanagedCallersOnlyDll [DllImport(nameof(UnmanagedCallersOnlyDll))] // Returns -1 if exception was throw and caught. public static extern int CallManagedProcCatchException(IntPtr callbackProc, int n); - - [UnmanagedCallersOnly] - [DllImport(nameof(UnmanagedCallersOnlyDll), EntryPoint = "DoesntExist")] - public static extern int PInvokeMarkedWithUnmanagedCallersOnly(int n); } private const string InvalidCSharpAssemblyName = "InvalidCSharp"; @@ -49,6 +45,12 @@ public static Type GetGenericClassOfIntType() return asm.GetType("InvalidCSharp.GenericClass`1").MakeGenericType(typeof(int)); } + public static Type GetCallingUnmanagedCallersOnlyDirectlyType() + { + var asm = Assembly.Load(InvalidCSharpAssemblyName); + return asm.GetType("InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly"); + } + private delegate int IntNativeMethodInvoker(); private delegate void NativeMethodInvoker(); @@ -347,7 +349,7 @@ public static void NegativeTest_ViaDelegate() // Local function to delay exception thrown during JIT void CallAsDelegate() { - Func invoker = ManagedDoubleCallback; + Func invoker = (Func)GetCallingUnmanagedCallersOnlyDirectlyType().GetMethod("GetDoubleDelegate").Invoke(null, BindingFlags.DoNotWrapExceptions, null, null, null); invoker(0); } } @@ -716,10 +718,11 @@ public static void TestPInvokeMarkedWithUnmanagedCallersOnly() Console.WriteLine($"Running {nameof(TestPInvokeMarkedWithUnmanagedCallersOnly)}..."); // Call P/Invoke directly - Assert.Throws(() => UnmanagedCallersOnlyDll.PInvokeMarkedWithUnmanagedCallersOnly(0)); + var pInvokeWrapperMethod = GetCallingUnmanagedCallersOnlyDirectlyType().GetMethod("CallPInvokeMarkedWithUnmanagedCallersOnly"); + Assert.Throws(() => pInvokeWrapperMethod.Invoke(null, BindingFlags.DoNotWrapExceptions, null, new[] { (object)0 }, null)); // Call P/Invoke via reflection - var method = typeof(UnmanagedCallersOnlyDll).GetMethod(nameof(UnmanagedCallersOnlyDll.PInvokeMarkedWithUnmanagedCallersOnly)); + var method = GetCallingUnmanagedCallersOnlyDirectlyType().GetMethod("PInvokeMarkedWithUnmanagedCallersOnly"); Assert.Throws(() => method.Invoke(null, BindingFlags.DoNotWrapExceptions, null, new[] { (object)0 }, null)); // Call P/Invoke as a function pointer @@ -728,7 +731,7 @@ void TestPInvokeMarkedWithUnmanagedCallersOnly_Throws() { .locals init (native int V_0) IL_0000: nop - IL_0001: ldftn int UnmanagedCallersOnlyDll.PInvokeMarkedWithUnmanagedCallersOnly(int32) + IL_0001: ldftn int InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::PInvokeMarkedWithUnmanagedCallersOnly(int32) IL_0007: stloc.0 IL_0008: ldc.i4 1234 From e0766bcbeee4d4dae28cb5c9ed41a4608327fbb5 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 Oct 2020 11:00:42 -0700 Subject: [PATCH 2/3] Fix direct project reference and clean up some reflection. --- .../UnmanagedCallersOnly/InvalidCallbacks.il | 20 +++++++--- .../UnmanagedCallersOnlyTest.cs | 40 +++++-------------- .../UnmanagedCallersOnlyTest.csproj | 1 + 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il index 487ad66f1a26c..2ba218b340268 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il +++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il @@ -1,8 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -.assembly extern System.Runtime { } -.assembly extern System.Runtime.InteropServices { } +.assembly extern System.Runtime +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) + .ver 5:0:0:0 +} +.assembly extern System.Runtime.InteropServices +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) + .ver 5:0:0:0 +} .assembly InvalidCSharp { } @@ -74,7 +82,7 @@ } } -.class public auto ansi beforefieldinit InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly +.class public auto ansi beforefieldinit InvalidCSharp.CallingUnmanagedCallersOnlyDirectly extends [System.Runtime]System.Object { .method public hidebysig specialname rtspecialname @@ -101,7 +109,7 @@ IL_0000: nop IL_0001: ldarg.0 - IL_0002: call int32 InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::DoubleImpl(int32) + IL_0002: call int32 InvalidCSharp.CallingUnmanagedCallersOnlyDirectly::DoubleImpl(int32) IL_0007: stloc.0 IL_0008: br.s IL_000a @@ -136,7 +144,7 @@ .maxstack 8 IL_0000: ldnull - IL_0001: ldftn int32 InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::ManagedDoubleCallback(int32) + IL_0001: ldftn int32 InvalidCSharp.CallingUnmanagedCallersOnlyDirectly::ManagedDoubleCallback(int32) IL_0007: newobj instance void class [System.Runtime]System.Func`2::.ctor(object, native int) IL_000c: ret } @@ -159,7 +167,7 @@ .maxstack 1 ldarg.0 - call int32 InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::PInvokeMarkedWithUnmanagedCallersOnly(int32) + call int32 InvalidCSharp.CallingUnmanagedCallersOnlyDirectly::PInvokeMarkedWithUnmanagedCallersOnly(int32) ret } } \ No newline at end of file diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs index 90616cb182f29..93ab29a5c1ea7 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Threading; using TestLibrary; +using InvalidCSharp; public class Program { @@ -31,26 +32,6 @@ public static class UnmanagedCallersOnlyDll public static extern int CallManagedProcCatchException(IntPtr callbackProc, int n); } - private const string InvalidCSharpAssemblyName = "InvalidCSharp"; - - public static Type GetCallbacksType() - { - var asm = Assembly.Load(InvalidCSharpAssemblyName); - return asm.GetType("InvalidCSharp.Callbacks"); - } - - public static Type GetGenericClassOfIntType() - { - var asm = Assembly.Load(InvalidCSharpAssemblyName); - return asm.GetType("InvalidCSharp.GenericClass`1").MakeGenericType(typeof(int)); - } - - public static Type GetCallingUnmanagedCallersOnlyDirectlyType() - { - var asm = Assembly.Load(InvalidCSharpAssemblyName); - return asm.GetType("InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly"); - } - private delegate int IntNativeMethodInvoker(); private delegate void NativeMethodInvoker(); @@ -349,7 +330,7 @@ public static void NegativeTest_ViaDelegate() // Local function to delay exception thrown during JIT void CallAsDelegate() { - Func invoker = (Func)GetCallingUnmanagedCallersOnlyDirectlyType().GetMethod("GetDoubleDelegate").Invoke(null, BindingFlags.DoNotWrapExceptions, null, null, null); + Func invoker = CallingUnmanagedCallersOnlyDirectly.GetDoubleDelegate(); invoker(0); } } @@ -364,7 +345,7 @@ void TestUnmanagedCallersOnlyNonStatic() { .locals init ([0] native int ptr) nop - ldftn int GetCallbacksType().CallbackNonStatic(int) + ldftn int typeof(Callbacks).CallbackNonStatic(int) stloc.0 ldloc.0 @@ -381,7 +362,7 @@ ldftn int GetCallbacksType().CallbackNonStatic(int) il.Emit(OpCodes.Nop); // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackNonStatic")); + il.Emit(OpCodes.Ldftn, typeof(Callbacks).GetMethod("CallbackNonStatic")); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); @@ -466,7 +447,7 @@ .locals init ([0] native int ptr) il.Emit(OpCodes.Nop); // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackMethodGeneric")); + il.Emit(OpCodes.Ldftn, typeof(Callbacks).GetMethod("CallbackMethodGeneric")); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ret); @@ -502,7 +483,7 @@ ldftn void InvalidCSharp.Callbacks.CallbackMethodGeneric(int) il.Emit(OpCodes.Nop); // Get native function pointer of the instantiated generic callback - il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackMethodGeneric").MakeGenericMethod(new [] { typeof(int) })); + il.Emit(OpCodes.Ldftn, typeof(Callbacks).GetMethod("CallbackMethodGeneric").MakeGenericMethod(new [] { typeof(int) })); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); @@ -544,7 +525,7 @@ .locals init ([0] native int ptr) il.Emit(OpCodes.Nop); // Get native function pointer of the callback from the instantiated generic class. - il.Emit(OpCodes.Ldftn, GetGenericClassOfIntType().GetMethod("CallbackMethod")); + il.Emit(OpCodes.Ldftn, typeof(GenericClass).GetMethod("CallbackMethod")); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); @@ -718,11 +699,10 @@ public static void TestPInvokeMarkedWithUnmanagedCallersOnly() Console.WriteLine($"Running {nameof(TestPInvokeMarkedWithUnmanagedCallersOnly)}..."); // Call P/Invoke directly - var pInvokeWrapperMethod = GetCallingUnmanagedCallersOnlyDirectlyType().GetMethod("CallPInvokeMarkedWithUnmanagedCallersOnly"); - Assert.Throws(() => pInvokeWrapperMethod.Invoke(null, BindingFlags.DoNotWrapExceptions, null, new[] { (object)0 }, null)); + Assert.Throws(() => CallingUnmanagedCallersOnlyDirectly.CallPInvokeMarkedWithUnmanagedCallersOnly(0)); // Call P/Invoke via reflection - var method = GetCallingUnmanagedCallersOnlyDirectlyType().GetMethod("PInvokeMarkedWithUnmanagedCallersOnly"); + var method = typeof(CallingUnmanagedCallersOnlyDirectly).GetMethod(nameof(CallingUnmanagedCallersOnlyDirectly.PInvokeMarkedWithUnmanagedCallersOnly)); Assert.Throws(() => method.Invoke(null, BindingFlags.DoNotWrapExceptions, null, new[] { (object)0 }, null)); // Call P/Invoke as a function pointer @@ -731,7 +711,7 @@ void TestPInvokeMarkedWithUnmanagedCallersOnly_Throws() { .locals init (native int V_0) IL_0000: nop - IL_0001: ldftn int InvalidCSharp.CallingUnmanagedCalllersOnlyDirectly::PInvokeMarkedWithUnmanagedCallersOnly(int32) + IL_0001: ldftn int InvalidCSharp.CallingUnmanagedCallersOnlyDirectly::PInvokeMarkedWithUnmanagedCallersOnly(int32) IL_0007: stloc.0 IL_0008: ldc.i4 1234 diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj index 170fac3899124..72c30ff8cdb7e 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj @@ -1,6 +1,7 @@ Exe + true From efa77d00ec75e0b71a8eea7b677baefc432146db Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 4 Nov 2020 15:20:19 -0800 Subject: [PATCH 3/3] Remove unnecessary version. Signed-off-by: Jeremy Koritzinsky --- src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il index 2ba218b340268..f85723a9fcaa0 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il +++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il @@ -4,12 +4,10 @@ .assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) - .ver 5:0:0:0 } .assembly extern System.Runtime.InteropServices { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) - .ver 5:0:0:0 } .assembly InvalidCSharp { }