From 3036986babe34a518a9eaf436c1273459dc817a1 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 11 Sep 2020 16:26:41 -0700 Subject: [PATCH 1/3] Convert invalid C# uses of UnmanagedCallersOnly to IL for negative testing. --- .../UnmanagedCallersOnly/InvalidCSharp.ilproj | 8 ++ .../UnmanagedCallersOnly/InvalidCallbacks.il | 75 +++++++++++++++++++ .../UnmanagedCallersOnlyTest.cs | 56 +++++++------- .../UnmanagedCallersOnlyTest.csproj | 2 +- 4 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj create mode 100644 src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj b/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj new file mode 100644 index 00000000000000..b7b8b4d7665382 --- /dev/null +++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj @@ -0,0 +1,8 @@ + + + library + + + + + \ No newline at end of file diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il new file mode 100644 index 00000000000000..a2ba0962d95d10 --- /dev/null +++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il @@ -0,0 +1,75 @@ +// 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 InvalidCSharp.dll { } + +.class public auto ansi beforefieldinit InvalidCSharp.GenericClass`1 + extends System.Object +{ + .method public hidebysig static + void CallbackMethod ( + int32 n + ) cil managed preservesig + { + .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + .maxstack 8 + IL_0000: ldstr "Functions with attribute UnmanagedCallersOnlyAttribute within a generic type are invalid" + IL_0005: newobj instance void [System.Runtime]System.Exception::.ctor(string) + IL_000a: throw + } + + .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 + } +} + +.class public auto ansi beforefieldinit InvalidCSharp.Callbacks + extends [System.Runtime]System.Object +{ + .method public hidebysig static + int32 CallbackMethodGeneric ( + !!T arg + ) cil managed preservesig + { + .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + .maxstack 8 + IL_0000: ldstr "Functions with attribute UnmanagedCallersOnlyAttribute cannot have generic arguments" + IL_0005: newobj instance void [System.Runtime]System.Exception::.ctor(string) + IL_000a: throw + } + + .method public hidebysig + instance int32 CallbackNonStatic ( + int32 val + ) cil managed preservesig + { + .custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + .maxstack 8 + IL_0000: ldstr "Instance functions with attribute UnmanagedCallersOnlyAttribute are invalid" + IL_0005: newobj instance void [System.Runtime]System.Exception::.ctor(string) + IL_000a: throw + } + + .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 + } +} diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs index 68d700c9ccfa96..c419dabb5a9e0f 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -3,9 +3,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; +using System.IO; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Runtime.Loader; using System.Runtime.InteropServices; using System.Threading; using TestLibrary; @@ -35,6 +37,20 @@ public static class UnmanagedCallersOnlyDll public static extern int PInvokeMarkedWithUnmanagedCallersOnly(int n); } + private const string InvalidCSharpAssemblyName = "InvalidCSharp.dll"; + + public static Type GetCallbacksType() + { + var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(Environment.CurrentDirectory, InvalidCSharpAssemblyName)); + return asm.GetType("InvalidCSharp.Callbacks"); + } + + public static Type GetGenericClassOfIntType() + { + var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(Environment.CurrentDirectory, InvalidCSharpAssemblyName)); + return asm.GetType("InvalidCSharp.GenericClass`1").MakeGenericType(typeof(int)); + } + private delegate int IntNativeMethodInvoker(); private delegate void NativeMethodInvoker(); @@ -338,12 +354,6 @@ void CallAsDelegate() } } - [UnmanagedCallersOnly] - public int CallbackNonStatic(int val) - { - Assert.Fail($"Instance functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} are invalid"); - return -1; - } public static void NegativeTest_NonStaticMethod() { @@ -354,7 +364,7 @@ void TestUnmanagedCallersOnlyNonStatic() { .locals init ([0] native int ptr) nop - ldftn int CallbackNonStatic(int) + ldftn int GetCallbacksType().CallbackNonStatic(int) stloc.0 ldloc.0 @@ -371,7 +381,7 @@ ldftn int CallbackNonStatic(int) il.Emit(OpCodes.Nop); // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackNonStatic))); + il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackNonStatic")); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); @@ -436,13 +446,6 @@ ldftn int CallbackMethodNonBlittable(bool) Assert.Throws(() => { testNativeMethod(); }); } - [UnmanagedCallersOnly] - public static int CallbackMethodGeneric(T arg) - { - Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} cannot have generic arguments"); - return -1; - } - public static void NegativeTest_NonInstantiatedGenericArguments() { Console.WriteLine($"Running {nameof(NegativeTest_NonInstantiatedGenericArguments)}..."); @@ -452,7 +455,7 @@ void TestUnmanagedCallersOnlyNonInstGenericArguments() { .locals init ([0] native int ptr) IL_0000: nop - IL_0001: ldftn void CallbackMethodGeneric(T) + IL_0001: ldftn void InvalidCSharp.Callbacks.CallbackMethodGeneric(T) IL_0007: stloc.0 IL_0008: ret } @@ -463,7 +466,7 @@ .locals init ([0] native int ptr) il.Emit(OpCodes.Nop); // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric))); + il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackMethodGeneric")); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ret); @@ -482,7 +485,7 @@ void TestUnmanagedCallersOnlyInstGenericArguments() { .locals init ([0] native int ptr) nop - ldftn void CallbackMethodGeneric(int) + ldftn void InvalidCSharp.Callbacks.CallbackMethodGeneric(int) stloc.0 ldloc.0 @@ -499,7 +502,7 @@ ldftn void CallbackMethodGeneric(int) il.Emit(OpCodes.Nop); // Get native function pointer of the instantiated generic callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric)).MakeGenericMethod(new [] { typeof(int) })); + il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackMethodGeneric").MakeGenericMethod(new [] { typeof(int) })); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); @@ -515,15 +518,6 @@ ldftn void CallbackMethodGeneric(int) Assert.Throws(() => { testNativeMethod(); }); } - public class GenericClass - { - [UnmanagedCallersOnly] - public static void CallbackMethod(int n) - { - Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} within a generic type are invalid"); - } - } - public static void NegativeTest_FromInstantiatedGenericClass() { Console.WriteLine($"Running {nameof(NegativeTest_FromInstantiatedGenericClass)}..."); @@ -533,7 +527,7 @@ void TestUnmanagedCallersOnlyInstGenericType() { .locals init ([0] native int ptr) nop - ldftn int GenericClass::CallbackMethod(int) + ldftn int InvalidCSharp.GenericClass::CallbackMethod(int) stloc.0 ldloc.0 @@ -550,7 +544,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, typeof(GenericClass).GetMethod(nameof(GenericClass.CallbackMethod))); + il.Emit(OpCodes.Ldftn, GetGenericClassOfIntType().GetMethod("CallbackMethod")); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj index a8c1862cc6f6c7..170fac3899124b 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj @@ -1,7 +1,6 @@ Exe - 1 @@ -10,5 +9,6 @@ + From 23e6b2f4f8387911a03b1f72daf4f42138016404 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 11 Sep 2020 16:43:12 -0700 Subject: [PATCH 2/3] PR feedback --- src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il | 2 +- .../UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il index a2ba0962d95d10..bd391367f52332 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il +++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCallbacks.il @@ -4,7 +4,7 @@ .assembly extern System.Runtime { } .assembly extern System.Runtime.InteropServices { } -.assembly InvalidCSharp.dll { } +.assembly InvalidCSharp { } .class public auto ansi beforefieldinit InvalidCSharp.GenericClass`1 extends System.Object diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs index c419dabb5a9e0f..e96d84f0c20d81 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -3,11 +3,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; -using System.Runtime.Loader; using System.Runtime.InteropServices; using System.Threading; using TestLibrary; @@ -41,13 +39,13 @@ public static class UnmanagedCallersOnlyDll public static Type GetCallbacksType() { - var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(Environment.CurrentDirectory, InvalidCSharpAssemblyName)); + var asm = Assembly.Load("InvalidCSharp"); return asm.GetType("InvalidCSharp.Callbacks"); } public static Type GetGenericClassOfIntType() { - var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(Environment.CurrentDirectory, InvalidCSharpAssemblyName)); + var asm = Assembly.Load("InvalidCSharp"); return asm.GetType("InvalidCSharp.GenericClass`1").MakeGenericType(typeof(int)); } From fa02c1819d267d92b5b4bd3361546d19546b11cc Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 11 Sep 2020 17:01:06 -0700 Subject: [PATCH 3/3] Nit issue. --- .../UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs index e96d84f0c20d81..0a2b5307da315e 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -35,17 +35,17 @@ public static class UnmanagedCallersOnlyDll public static extern int PInvokeMarkedWithUnmanagedCallersOnly(int n); } - private const string InvalidCSharpAssemblyName = "InvalidCSharp.dll"; + private const string InvalidCSharpAssemblyName = "InvalidCSharp"; public static Type GetCallbacksType() { - var asm = Assembly.Load("InvalidCSharp"); + var asm = Assembly.Load(InvalidCSharpAssemblyName); return asm.GetType("InvalidCSharp.Callbacks"); } public static Type GetGenericClassOfIntType() { - var asm = Assembly.Load("InvalidCSharp"); + var asm = Assembly.Load(InvalidCSharpAssemblyName); return asm.GetType("InvalidCSharp.GenericClass`1").MakeGenericType(typeof(int)); }