From b910310f066d57e5290d5c3a96d64f03dfdd63c6 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Sat, 12 Sep 2020 19:39:29 -0700 Subject: [PATCH] Convert invalid C# uses of UnmanagedCallersOnly to IL. (#42146) * Convert invalid C# uses of UnmanagedCallersOnly to IL for negative testing. --- .../UnmanagedCallersOnly/InvalidCSharp.ilproj | 8 ++ .../UnmanagedCallersOnly/InvalidCallbacks.il | 75 +++++++++++++++++++ .../UnmanagedCallersOnlyTest.cs | 54 ++++++------- .../UnmanagedCallersOnlyTest.csproj | 2 +- 4 files changed, 107 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..bd391367f52332 --- /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 { } + +.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..0a2b5307da315e 100644 --- a/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs +++ b/src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using TestLibrary; @@ -35,6 +35,20 @@ public static class UnmanagedCallersOnlyDll public static extern int PInvokeMarkedWithUnmanagedCallersOnly(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)); + } + private delegate int IntNativeMethodInvoker(); private delegate void NativeMethodInvoker(); @@ -338,12 +352,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 +362,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 +379,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 +444,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 +453,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 +464,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 +483,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 +500,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 +516,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 +525,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 +542,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 @@ +