From 5a6a0362daa06bfdea439ebecf17c01291002b5a Mon Sep 17 00:00:00 2001 From: Zeng Jiang Date: Fri, 16 Nov 2018 15:46:51 +0800 Subject: [PATCH] Add PInvoke/CriticalHandles tests (#19297) * Add PInvoke/CreticalHandles tests * Bring up to current infrastructure. * Fix ReverseTest. --- tests/src/Interop/CMakeLists.txt | 1 + .../PInvoke/CriticalHandles/ArrayTest/ArrayTest.cs | 157 ++++++++ .../CriticalHandles/ArrayTest/ArrayTest.csproj | 34 ++ .../Interop/PInvoke/CriticalHandles/CMakeLists.txt | 13 + .../CriticalHandles/CriticalHandlesNative.cpp | 78 ++++ .../CriticalHandles/ReverseTest/ReverseTest.cs | 153 ++++++++ .../CriticalHandles/ReverseTest/ReverseTest.csproj | 34 ++ .../CriticalHandles/StructTest/StructTest.cs | 201 +++++++++++ .../CriticalHandles/StructTest/StructTest.csproj | 34 ++ .../Interop/PInvoke/CriticalHandles/Test/Test.cs | 393 +++++++++++++++++++++ .../PInvoke/CriticalHandles/Test/Test.csproj | 34 ++ 11 files changed, 1132 insertions(+) create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.cs create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.csproj create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/CMakeLists.txt create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/CriticalHandlesNative.cpp create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.cs create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.csproj create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.csproj create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/Test/Test.cs create mode 100644 tests/src/Interop/PInvoke/CriticalHandles/Test/Test.csproj diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 1ecb281..d49da33 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -27,6 +27,7 @@ add_subdirectory(PInvoke/Array/MarshalArrayAsParam/LPArrayNative) add_subdirectory(PInvoke/Miscellaneous/HandleRef) add_subdirectory(PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke) add_subdirectory(PInvoke/ExactSpelling) +add_subdirectory(PInvoke/CriticalHandles) add_subdirectory(PInvoke/AsAny) add_subdirectory(NativeCallable) add_subdirectory(PrimitiveMarshalling/Bool) diff --git a/tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.cs b/tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.cs new file mode 100644 index 0000000..fb3918c --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.cs @@ -0,0 +1,157 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using TestLibrary; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +internal class MyCriticalHandle : CriticalHandle +{ + static int s_uniqueHandleValue; + static HashSet s_closedHandles = new HashSet(); + + public MyCriticalHandle() : base(new IntPtr(-1)) + { + + } + + public override bool IsInvalid + { + get { return false; } + } + + protected override bool ReleaseHandle() + { + if (!s_closedHandles.Contains(handle.ToInt32())) + { + s_closedHandles.Add(handle.ToInt32()); + return true; + } + + return false; + } + + internal IntPtr Handle + { + get + { + return handle; + } + set + { + handle = value; + } + } + + internal static IntPtr GetUniqueHandle() + { + return new IntPtr(s_uniqueHandleValue++); + } + + internal static bool IsHandleClosed(IntPtr handle) + { + return s_closedHandles.Contains(handle.ToInt32()); + } +} + +internal class Native +{ + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.Bool)]internal delegate bool IsHandleClosed(IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr In([MarshalAs(UnmanagedType.LPArray)]MyCriticalHandle[] handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void Out(IntPtr handleValue, [MarshalAs(UnmanagedType.LPArray)]out MyCriticalHandle[] handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "Ref", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr InRef([In, MarshalAs(UnmanagedType.LPArray)]ref MyCriticalHandle[] handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr Ref([MarshalAs(UnmanagedType.LPArray)]ref MyCriticalHandle[] handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr RefModify(IntPtr handleValue, [MarshalAs(UnmanagedType.LPArray)]ref MyCriticalHandle[] handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern MyCriticalHandle[] Ret(IntPtr handleValue); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr SetIsHandleClosedCallback([MarshalAs(UnmanagedType.FunctionPtr)]IsHandleClosed isHandleClosed); +} + +public class CriticalHandleArrayTest +{ + private static Native.IsHandleClosed s_isHandleClose = (handleValue) => + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + return MyCriticalHandle.IsHandleClosed(handleValue); + }; + + public static void In() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + MyCriticalHandle[] myCriticalHandleArray = new MyCriticalHandle[] { new MyCriticalHandle() { Handle = handleValue } }; + Assert.Throws(() => Native.In(myCriticalHandleArray)); + } + + public static void Ret() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + Assert.Throws(() => Native.Ret(handleValue)); + } + + public static void Out() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + MyCriticalHandle[] myCriticalHandleArray; + Assert.Throws(() => Native.Out(handleValue, out myCriticalHandleArray)); + } + + public static void InRef() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + MyCriticalHandle[] myCriticalHandleArray = new MyCriticalHandle[] { new MyCriticalHandle() { Handle = handleValue } }; + Assert.Throws(() => Native.InRef(ref myCriticalHandleArray)); + } + + public static void Ref() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + MyCriticalHandle[] myCriticalHandleArray = new MyCriticalHandle[] { new MyCriticalHandle() { Handle = handleValue } }; + Assert.Throws(() => Native.Ref(ref myCriticalHandleArray)); + } + + public static void RefModify() + { + IntPtr handleValue1 = MyCriticalHandle.GetUniqueHandle(); + IntPtr handleValue2 = MyCriticalHandle.GetUniqueHandle(); + MyCriticalHandle[] myCriticalHandleArray = new MyCriticalHandle[] { new MyCriticalHandle() { Handle = handleValue1 } }; + Assert.Throws(() => Native.RefModify(handleValue2, ref myCriticalHandleArray)); + } + + public static int Main(string[] args) + { + try + { + In(); + Ret(); + Out(); + InRef(); + Ref(); + RefModify(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} diff --git a/tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.csproj b/tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.csproj new file mode 100644 index 0000000..47bbbc2 --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + ArrayTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/CriticalHandles/CMakeLists.txt b/tests/src/Interop/PInvoke/CriticalHandles/CMakeLists.txt new file mode 100644 index 0000000..2dfa7e4 --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/CMakeLists.txt @@ -0,0 +1,13 @@ +#VCXPROJ +cmake_minimum_required (VERSION 2.6) +project (CriticalHandlesNative) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + CriticalHandlesNative.cpp +) +# add the executable +add_library (CriticalHandlesNative SHARED ${SOURCES}) +target_link_libraries(CriticalHandlesNative ${LINK_LIBRARIES_ADDITIONAL}) +# add the install targets +install (TARGETS CriticalHandlesNative DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/CriticalHandles/CriticalHandlesNative.cpp b/tests/src/Interop/PInvoke/CriticalHandles/CriticalHandlesNative.cpp new file mode 100644 index 0000000..ec6ecb3 --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/CriticalHandlesNative.cpp @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include + +typedef BOOL(__stdcall *HandleCallback)(void*); + +extern "C" DLL_EXPORT size_t __stdcall In(void* handle, HandleCallback handleCallback) +{ + if (handleCallback != nullptr && !handleCallback(handle)) + { + return (size_t)(-1); + } + + return reinterpret_cast(handle); +} + +extern "C" DLL_EXPORT void* __stdcall Ret(void* handleValue) +{ + return handleValue; +} + +extern "C" DLL_EXPORT void __stdcall Out(void* handleValue, void** pHandle) +{ + if (pHandle == nullptr) + { + return; + } + + *pHandle = handleValue; +} + +extern "C" DLL_EXPORT size_t __stdcall Ref(void** pHandle, HandleCallback handleCallback) +{ + if (handleCallback != nullptr && !handleCallback(*pHandle)) + { + return (size_t)(-1); + } + + return reinterpret_cast(*pHandle); +} + +extern "C" DLL_EXPORT size_t __stdcall RefModify(void* handleValue, void** pHandle, HandleCallback handleCallback) +{ + if (handleCallback != nullptr && !handleCallback(*pHandle)) + { + return (size_t)(-1); + } + + void* originalHandle = *pHandle; + + *pHandle = handleValue; + + return reinterpret_cast(originalHandle); +} + +typedef void(__stdcall *InCallback)(void*); + +extern "C" DLL_EXPORT void __stdcall InvokeInCallback(InCallback callback, void* handle) +{ + callback(handle); +} + +typedef void(__stdcall *RefCallback)(void**); + +extern "C" DLL_EXPORT void __stdcall InvokeRefCallback(RefCallback callback, void** pHandle) +{ + callback(pHandle); +} + +typedef void*(__stdcall *RetCallback)(); + +extern "C" DLL_EXPORT void* __stdcall InvokeRetCallback(RetCallback callback) +{ + return callback(); +} diff --git a/tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.cs b/tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.cs new file mode 100644 index 0000000..8fefa0f --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.cs @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using TestLibrary; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +internal class MyCriticalHandle : CriticalHandle +{ + static int s_uniqueHandleValue; + static HashSet s_closedHandles = new HashSet(); + + public MyCriticalHandle() : base(new IntPtr(-1)) + { + + } + + public override bool IsInvalid + { + get { return false; } + } + + protected override bool ReleaseHandle() + { + if (!s_closedHandles.Contains(handle.ToInt32())) + { + s_closedHandles.Add(handle.ToInt32()); + return true; + } + + return false; + } + + internal IntPtr Handle + { + get + { + return handle; + } + set + { + handle = value; + } + } + + internal static IntPtr GetUniqueHandle() + { + return new IntPtr(s_uniqueHandleValue++); + } + + internal static bool IsHandleClosed(IntPtr handle) + { + return s_closedHandles.Contains(handle.ToInt32()); + } +} + +public class Reverse +{ + public static void In() + { + IntPtr handleValue = new IntPtr(1); + Native.InCallback callback = (handle) => { }; + Assert.Throws(() => Native.InvokeInCallback(callback, handleValue), "Calling P/Invoke that invokes a delegate that has an CriticalHandle parameter"); + GC.KeepAlive(callback); + } + + public static void Ret() + { + IntPtr handleValue = new IntPtr(2); + Native.RetCallback callback = () => new MyCriticalHandle(); + Assert.Throws(() => Native.InvokeRetCallback(callback), "Calling P/Invoke that invokes a delegate that returns a CriticalHandle parameter"); + GC.KeepAlive(callback); + } + + public static void Out() + { + IntPtr handleValue = new IntPtr(3); + Native.OutCallback callback = (out MyCriticalHandle handle) => handle = null; + Assert.Throws(() => Native.InvokeOutCallback(callback, ref handleValue), "Calling P/Invoke that invokes a delegate that has an out CriticalHandle parameter"); + GC.KeepAlive(callback); + } + + public static void InRef() + { + IntPtr handleValue = new IntPtr(4); + Native.InRefCallback callback = (ref MyCriticalHandle handle) => { }; + Assert.Throws(() => Native.InvokeInRefCallback(callback, ref handleValue), "Calling P/Invoke that invokes a delegate that has an [In] ref CriticalHandle parameter"); + GC.KeepAlive(callback); + } + + public static void Ref() + { + IntPtr handleValue = new IntPtr(5); + Native.RefCallback callback = (ref MyCriticalHandle handle) => { }; + Assert.Throws(() => Native.InvokeRefCallback(callback, ref handleValue), "Calling P/Invoke that invokes a delegate that has an ref CriticalHandle parameter"); + GC.KeepAlive(callback); + } + + internal class Native + { + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + internal delegate void InCallback(MyCriticalHandle handle); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + internal delegate void OutCallback(out MyCriticalHandle handle); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + internal delegate void InRefCallback([In]ref MyCriticalHandle handle); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + internal delegate void RefCallback(ref MyCriticalHandle handle); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + internal delegate MyCriticalHandle RetCallback(); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void InvokeInCallback(InCallback callback, IntPtr handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "InvokeRefCallback", CallingConvention = CallingConvention.StdCall)] + internal static extern void InvokeOutCallback(OutCallback callback, ref IntPtr handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "InvokeRefCallback", CallingConvention = CallingConvention.StdCall)] + internal static extern void InvokeInRefCallback(InRefCallback callback, ref IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void InvokeRefCallback(RefCallback callback, ref IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr InvokeRetCallback(RetCallback callback); + } + + public static int Main(string[] args) + { + try + { + In(); + Ret(); + Out(); + InRef(); + Ref(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} diff --git a/tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.csproj b/tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.csproj new file mode 100644 index 0000000..0c25efe --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/ReverseTest/ReverseTest.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + ReverseTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs b/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs new file mode 100644 index 0000000..abd2c3f --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs @@ -0,0 +1,201 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using TestLibrary; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +internal class MyCriticalHandle : CriticalHandle +{ + static int s_uniqueHandleValue; + static HashSet s_closedHandles = new HashSet(); + + public MyCriticalHandle() : base(new IntPtr(-1)) + { + + } + + public override bool IsInvalid + { + get { return false; } + } + + protected override bool ReleaseHandle() + { + if (!s_closedHandles.Contains(handle.ToInt32())) + { + s_closedHandles.Add(handle.ToInt32()); + return true; + } + + return false; + } + + internal IntPtr Handle + { + get + { + return handle; + } + set + { + handle = value; + } + } + + internal static IntPtr GetUniqueHandle() + { + return new IntPtr(s_uniqueHandleValue++); + } + + internal static bool IsHandleClosed(IntPtr handle) + { + return s_closedHandles.Contains(handle.ToInt32()); + } +} + +public class CriticalHandleStructTest +{ + private static Native.HandleCallback s_handleCallback = (handleValue) => + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + return !MyCriticalHandle.IsHandleClosed(handleValue); + }; + + public static void In() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + InWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void InWorker(IntPtr handleValue) + { + Native.MyCriticalHandleStruct handleStruct = new Native.MyCriticalHandleStruct() { Handle = new MyCriticalHandle() { Handle = handleValue } }; + IntPtr value; + value = Native.In(handleStruct, s_handleCallback); + Assert.AreEqual(handleValue.ToInt32(), value.ToInt32(), "Handle value"); + } + + public static void Ret() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + Assert.Throws(() => Native.Ret(handleValue)); + } + + public static void Out() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + Native.MyCriticalHandleStruct handleStruct; + Assert.Throws(() => Native.Out(handleValue, out handleStruct)); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void OutWorker(IntPtr handleValue) + { + Native.MyCriticalHandleStruct handleStruct; + Native.Out(handleValue, out handleStruct); + Assert.AreEqual(handleValue.ToInt32(), handleStruct.Handle.Handle.ToInt32(), "Handle value"); + } + + public static void InRef() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + InRefWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void InRefWorker(IntPtr handleValue) + { + Native.MyCriticalHandleStruct handleStruct = new Native.MyCriticalHandleStruct() { Handle = new MyCriticalHandle() { Handle = handleValue } }; + Native.InRef(ref handleStruct, s_handleCallback); + Assert.AreEqual(handleValue.ToInt32(), handleStruct.Handle.Handle.ToInt32(), "Handle value"); + } + + public static void Ref() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + RefWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void RefWorker(IntPtr handleValue) + { + Native.MyCriticalHandleStruct handleStruct = new Native.MyCriticalHandleStruct() { Handle = new MyCriticalHandle() { Handle = handleValue } }; + Native.Ref(ref handleStruct, s_handleCallback); + Assert.AreEqual(handleValue.ToInt32(), handleStruct.Handle.Handle.ToInt32(), "Handle value"); + } + + public static void RefModify() + { + IntPtr handleValue1 = MyCriticalHandle.GetUniqueHandle(); + IntPtr handleValue2 = MyCriticalHandle.GetUniqueHandle(); + Native.MyCriticalHandleStruct handleStruct = new Native.MyCriticalHandleStruct() { Handle = new MyCriticalHandle() { Handle = handleValue1 } }; + + Assert.Throws(() => Native.RefModify(handleValue2, ref handleStruct, null)); + } + + internal class Native + { + [StructLayout(LayoutKind.Sequential)] + internal struct MyCriticalHandleStruct + { + internal MyCriticalHandle Handle; + } + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.Bool)] + internal delegate bool HandleCallback(IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr In(MyCriticalHandleStruct handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void Out(IntPtr handleValue, out MyCriticalHandleStruct handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "Ref", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr InRef([In]ref MyCriticalHandleStruct handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr Ref(ref MyCriticalHandleStruct handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr RefModify(IntPtr handleValue, ref MyCriticalHandleStruct handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern MyCriticalHandleStruct Ret(IntPtr handleValue); + } + + public static int Main(string[] args) + { + try + { + In(); + Ret(); + Out(); + InRef(); + Ref(); + RefModify(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} diff --git a/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.csproj b/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.csproj new file mode 100644 index 0000000..0be3beb --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + StructTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/CriticalHandles/Test/Test.cs b/tests/src/Interop/PInvoke/CriticalHandles/Test/Test.cs new file mode 100644 index 0000000..f510c64 --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/Test/Test.cs @@ -0,0 +1,393 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using TestLibrary; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +internal class MyCriticalHandle : CriticalHandle +{ + static int s_uniqueHandleValue; + static HashSet s_closedHandles = new HashSet(); + + public MyCriticalHandle() : base(new IntPtr(-1)) + { + + } + + public override bool IsInvalid + { + get { return false; } + } + + protected override bool ReleaseHandle() + { + if (!s_closedHandles.Contains(handle.ToInt32())) + { + s_closedHandles.Add(handle.ToInt32()); + return true; + } + + return false; + } + + internal IntPtr Handle + { + get + { + return handle; + } + set + { + handle = value; + } + } + + internal static IntPtr GetUniqueHandle() + { + return new IntPtr(s_uniqueHandleValue++); + } + + internal static bool IsHandleClosed(IntPtr handle) + { + return s_closedHandles.Contains(handle.ToInt32()); + } +} + +public abstract class AbstractCriticalHandle : CriticalHandle +{ + public AbstractCriticalHandle() : base(new IntPtr(-1)) + { + + } + + internal IntPtr Handle + { + get + { + return handle; + } + } +} + +public class CriticalHandleWithNoDefaultCtor : AbstractCriticalHandle +{ + public CriticalHandleWithNoDefaultCtor(IntPtr handle) + { + this.handle = handle; + } + + public override bool IsInvalid + { + get { return false; } + } + + protected override bool ReleaseHandle() + { + return true; + } +} + +public class CriticalHandleTest +{ + private static Native.HandleCallback s_handleCallback = (handleValue) => + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + return !MyCriticalHandle.IsHandleClosed(handleValue); + }; + + public static void In() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + InWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void InWorker(IntPtr handleValue) + { + MyCriticalHandle hande = new MyCriticalHandle() { Handle = handleValue }; + IntPtr value; + value = Native.In(hande, s_handleCallback); + Assert.AreEqual(handleValue.ToInt32(), value.ToInt32(), "Handle value"); + } + + public static void Ret() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + RetWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void RetWorker(IntPtr handleValue) + { + MyCriticalHandle hande = Native.Ret(handleValue); + Assert.AreEqual(handleValue.ToInt32(), hande.Handle.ToInt32(), "Handle value"); + } + + public static void Out() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + OutWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void OutWorker(IntPtr handleValue) + { + MyCriticalHandle hande; + Native.Out(handleValue, out hande); + Assert.AreEqual(handleValue.ToInt32(), hande.Handle.ToInt32(), "Handle value"); + } + + public static void InRef() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + InRefWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void InRefWorker(IntPtr handleValue) + { + MyCriticalHandle hande = new MyCriticalHandle() { Handle = handleValue }; + Native.InRef(ref hande, s_handleCallback); + Assert.AreEqual(handleValue.ToInt32(), hande.Handle.ToInt32(), "Handle value"); + } + + public static void Ref() + { + IntPtr handleValue = MyCriticalHandle.GetUniqueHandle(); + RefWorker(handleValue); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue), "Handle was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void RefWorker(IntPtr handleValue) + { + MyCriticalHandle hande = new MyCriticalHandle() { Handle = handleValue }; + Native.Ref(ref hande, s_handleCallback); + Assert.AreEqual(handleValue.ToInt32(), hande.Handle.ToInt32(), "Handle value"); + } + + public static void RefModify() + { + IntPtr handleValue1 = MyCriticalHandle.GetUniqueHandle(); + IntPtr handleValue2 = MyCriticalHandle.GetUniqueHandle(); + RefModifyWorker(handleValue1, handleValue2); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue1), "Handle 1 was not closed"); + Assert.IsTrue(MyCriticalHandle.IsHandleClosed(handleValue2), "Handle 2 was not closed"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void RefModifyWorker(IntPtr handleValue1, IntPtr handleValue2) + { + MyCriticalHandle hande = new MyCriticalHandle() { Handle = handleValue1 }; + Native.RefModify(handleValue2, ref hande, s_handleCallback); + Assert.AreEqual(handleValue2.ToInt32(), hande.Handle.ToInt32(), "Handle value"); + } + + internal class Native + { + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.Bool)] + internal delegate bool HandleCallback(IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr In(MyCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void Out(IntPtr handleValue, out MyCriticalHandle handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "Ref", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr InRef([In]ref MyCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr Ref(ref MyCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr RefModify(IntPtr handleValue, ref MyCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern MyCriticalHandle Ret(IntPtr handleValue); + } +} + +public class AbstractCriticalHandleTest +{ + public static void In() + { + IntPtr handleValue = new IntPtr(1); + AbstractCriticalHandle handle = new CriticalHandleWithNoDefaultCtor(handleValue); + IntPtr value; + value = Native.In(handle, null); + Assert.AreEqual(handleValue.ToInt32(), value.ToInt32(), "Handle value"); + } + + public static void Ret() + { + IntPtr handleValue = new IntPtr(2); + Assert.Throws(() => Native.Ret(handleValue), "Calling P/Invoke that returns an abstract critical handle"); + } + + public static void Out() + { + IntPtr handleValue = new IntPtr(3); + AbstractCriticalHandle handle; + Assert.Throws(() => Native.Out(handleValue, out handle), "Calling P/Invoke that has an out abstract critical handle parameter"); + } + + public static void InRef() + { + IntPtr handleValue = new IntPtr(4); + AbstractCriticalHandle handle = new CriticalHandleWithNoDefaultCtor(handleValue); + Native.InRef(ref handle, null); + Assert.AreEqual(handleValue.ToInt32(), handle.Handle.ToInt32(), "Handle value"); + } + + public static void Ref() + { + IntPtr handleValue = new IntPtr(5); + AbstractCriticalHandle handle = new CriticalHandleWithNoDefaultCtor(handleValue); + Assert.Throws(() => Native.Ref(ref handle, null), "Calling P/Invoke that has a ref abstract critical handle parameter"); + } + + internal class Native + { + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.Bool)] + internal delegate bool HandleCallback(IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr In(AbstractCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void Out(IntPtr handleValue, out AbstractCriticalHandle handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "Ref", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr InRef([In]ref AbstractCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr Ref(ref AbstractCriticalHandle handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern AbstractCriticalHandle Ret(IntPtr handleValue); + } +} + +public class NoDefaultCtorCriticalHandleTest +{ + public static void In() + { + IntPtr handleValue = new IntPtr(1); + CriticalHandleWithNoDefaultCtor handle = new CriticalHandleWithNoDefaultCtor(handleValue); + IntPtr value; + value = Native.In(handle, null); + Assert.AreEqual(handleValue.ToInt32(), value.ToInt32(), "Handle value"); + } + + public static void Ret() + { + IntPtr handleValue = new IntPtr(2); + //TODO: Expected MissingMemberException but throws MissingMethodException + Assert.Throws(() => Native.Ret(handleValue), "Calling P/Invoke that returns an no default ctor critical handle"); + } + + public static void Out() + { + IntPtr handleValue = new IntPtr(3); + CriticalHandleWithNoDefaultCtor handle; + //TODO: Expected MissingMemberException but throws MissingMethodException + Assert.Throws(() => Native.Out(handleValue, out handle), "Calling P/Invoke that has an out no default ctor critical handle parameter"); + } + + public static void InRef() + { + IntPtr handleValue = new IntPtr(4); + CriticalHandleWithNoDefaultCtor handle = new CriticalHandleWithNoDefaultCtor(handleValue); + //TODO: Expected MissingMemberException but throws MissingMethodException + Assert.Throws(() => Native.InRef(ref handle, null), "Calling P/Invoke that has a [In] ref no default ctor critical handle parameter"); + } + + public static void Ref() + { + IntPtr handleValue = new IntPtr(5); + CriticalHandleWithNoDefaultCtor handle = new CriticalHandleWithNoDefaultCtor(handleValue); + //TODO: Expected MissingMemberException but throws MissingMethodException + Assert.Throws(() => Native.Ref(ref handle, null), "Calling P/Invoke that has a ref no default ctor critical handle parameter"); + } + + internal class Native + { + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.Bool)] + internal delegate bool HandleCallback(IntPtr handle); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr In(CriticalHandleWithNoDefaultCtor handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern void Out(IntPtr handleValue, out CriticalHandleWithNoDefaultCtor handle); + + [DllImport("CriticalHandlesNative", EntryPoint = "Ref", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr InRef([In]ref CriticalHandleWithNoDefaultCtor handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern IntPtr Ref(ref CriticalHandleWithNoDefaultCtor handle, HandleCallback handleCallback); + + [DllImport("CriticalHandlesNative", CallingConvention = CallingConvention.StdCall)] + internal static extern CriticalHandleWithNoDefaultCtor Ret(IntPtr handleValue); + } +} + +public class Test +{ + public static int Main(string[] args) + { + try + { + CriticalHandleTest.In(); + CriticalHandleTest.Ret(); + CriticalHandleTest.Out(); + CriticalHandleTest.InRef(); + CriticalHandleTest.Ref(); + CriticalHandleTest.RefModify(); + + AbstractCriticalHandleTest.In(); + AbstractCriticalHandleTest.Ret(); + AbstractCriticalHandleTest.Out(); + AbstractCriticalHandleTest.InRef(); + AbstractCriticalHandleTest.Ref(); + + NoDefaultCtorCriticalHandleTest.In(); + NoDefaultCtorCriticalHandleTest.Ret(); + NoDefaultCtorCriticalHandleTest.Out(); + NoDefaultCtorCriticalHandleTest.InRef(); + NoDefaultCtorCriticalHandleTest.Ref(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} diff --git a/tests/src/Interop/PInvoke/CriticalHandles/Test/Test.csproj b/tests/src/Interop/PInvoke/CriticalHandles/Test/Test.csproj new file mode 100644 index 0000000..1a442e3 --- /dev/null +++ b/tests/src/Interop/PInvoke/CriticalHandles/Test/Test.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + Test + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + + -- 2.7.4