From b3ff0e91236478221dda31b2c7ae1ca05754143c Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 16 Apr 2021 17:55:52 -0700 Subject: [PATCH 1/8] Add Get/SetLastPInvokeError and Get/SetLastSystemError APIs --- .../InteropServices/Marshal.CoreCLR.cs | 40 +++++++++++++++++-- src/coreclr/vm/ecalllist.h | 6 ++- src/coreclr/vm/marshalnative.cpp | 22 ++++++++-- src/coreclr/vm/marshalnative.h | 6 ++- .../Runtime/InteropServices/CriticalHandle.cs | 4 +- .../System/Runtime/InteropServices/Marshal.cs | 5 +++ .../Runtime/InteropServices/SafeHandle.cs | 4 +- .../ref/System.Runtime.InteropServices.cs | 4 ++ .../Runtime/InteropServices/Marshal.Mono.cs | 40 +++++++++++++++++-- src/mono/mono/metadata/icall-def-netcore.h | 6 ++- src/mono/mono/metadata/marshal.c | 28 +++++++++++-- src/mono/mono/metadata/marshal.h | 14 +++++-- 12 files changed, 150 insertions(+), 29 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs index afacc85d34c863..99ab0fd9c07ee9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs @@ -163,11 +163,43 @@ private static unsafe void WriteValueSlow(object ptr, int ofs, T val, Action< } } + /// + /// Get the last platform invoke error on the current thread + /// + /// The last platform invoke error + /// + /// The last platform invoke error corresponds to the error set by either the most recent platform + /// invoke that was configured to set the last error or a call to . + /// + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern int GetLastPInvokeError(); + + /// + /// Set the last platform invoke error on the current thread + /// + /// Error to set + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern void SetLastPInvokeError(int error); + + /// + /// Get the last system error on the current thread + /// + /// The last system error + /// + /// The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows) + /// [MethodImpl(MethodImplOptions.InternalCall)] - public static extern int GetLastWin32Error(); + public static extern int GetLastSystemError(); + /// + /// Set the last system error on the current thread + /// + /// Error to set + /// + /// The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows) + /// [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void SetLastWin32Error(int error); + public static extern void SetLastSystemError(int error); private static void PrelinkCore(MethodInfo m) { @@ -221,7 +253,7 @@ private static object PtrToStructureHelper(IntPtr ptr, Type structureType) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool IsPinnable(object? obj); -#if FEATURE_COMINTEROP +#if TARGET_WINDOWS /// /// Returns the HInstance for this module. Returns -1 if the module doesn't have /// an HInstance. In Memory (Dynamic) Modules won't have an HInstance. @@ -244,7 +276,7 @@ public static IntPtr GetHINSTANCE(Module m) [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] private static extern IntPtr GetHINSTANCE(QCallModule m); -#endif // FEATURE_COMINTEROP +#endif // TARGET_WINDOWS [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 9b84c7a8dd6b1b..2655205a2751ea 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -742,8 +742,10 @@ FCFuncStart(gGCSettingsFuncs) FCFuncEnd() FCFuncStart(gInteropMarshalFuncs) - FCFuncElement("GetLastWin32Error", MarshalNative::GetLastWin32Error) - FCFuncElement("SetLastWin32Error", MarshalNative::SetLastWin32Error) + FCFuncElement("GetLastPInvokeError", MarshalNative::GetLastPInvokeError) + FCFuncElement("SetLastPInvokeError", MarshalNative::SetLastPInvokeError) + FCFuncElement("GetLastSystemError", MarshalNative::GetLastSystemError) + FCFuncElement("SetLastSystemError", MarshalNative::SetLastSystemError) FCFuncElement("SizeOfHelper", MarshalNative::SizeOfClass) FCFuncElement("StructureToPtr", MarshalNative::StructureToPtr) FCFuncElement("PtrToStructureHelper", MarshalNative::PtrToStructureHelper) diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp index 3f247dca44d7c8..f0d47cb1030ac2 100644 --- a/src/coreclr/vm/marshalnative.cpp +++ b/src/coreclr/vm/marshalnative.cpp @@ -405,9 +405,9 @@ FCIMPL1(LPVOID, MarshalNative::GetFunctionPointerForDelegateInternal, Object* re FCIMPLEND /************************************************************************ - * PInvoke.GetLastWin32Error + * Marshal.GetLastPInvokeError */ -FCIMPL0(int, MarshalNative::GetLastWin32Error) +FCIMPL0(int, MarshalNative::GetLastPInvokeError) { FCALL_CONTRACT; @@ -417,9 +417,9 @@ FCIMPLEND /************************************************************************ - * PInvoke.SetLastWin32Error + * Marshal.SetLastPInvokeError */ -FCIMPL1(void, MarshalNative::SetLastWin32Error, int error) +FCIMPL1(void, MarshalNative::SetLastPInvokeError, int error) { FCALL_CONTRACT; @@ -427,6 +427,20 @@ FCIMPL1(void, MarshalNative::SetLastWin32Error, int error) } FCIMPLEND +FCIMPL0(int, MarshalNative::GetLastSystemError) +{ + FCALL_CONTRACT; + return ::GetLastError(); +} +FCIMPLEND + +FCIMPL1(void, MarshalNative::SetLastSystemError, int error) +{ + FCALL_CONTRACT; + ::SetLastError(error); +} +FCIMPLEND + /************************************************************************ * Support for the GCHandle class. diff --git a/src/coreclr/vm/marshalnative.h b/src/coreclr/vm/marshalnative.h index fc92e26028a7fb..51ff113d4c32fb 100644 --- a/src/coreclr/vm/marshalnative.h +++ b/src/coreclr/vm/marshalnative.h @@ -30,8 +30,10 @@ class MarshalNative static FCDECL2(UINT32, SizeOfClass, ReflectClassBaseObject* refClass, CLR_BOOL throwIfNotMarshalable); static FCDECL1(UINT32, OffsetOfHelper, ReflectFieldObject* pFieldUNSAFE); - static FCDECL0(int, GetLastWin32Error); - static FCDECL1(void, SetLastWin32Error, int error); + static FCDECL0(int, GetLastPInvokeError); + static FCDECL1(void, SetLastPInvokeError, int error); + static FCDECL0(int, GetLastSystemError); + static FCDECL1(void, SetLastSystemError, int error); static FCDECL3(VOID, StructureToPtr, Object* pObjUNSAFE, LPVOID ptr, CLR_BOOL fDeleteOld); static FCDECL3(VOID, PtrToStructureHelper, LPVOID ptr, Object* pObjIn, CLR_BOOL allowValueClasses); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CriticalHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CriticalHandle.cs index bded46e242b6f8..0fe1dc698fd0a6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CriticalHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CriticalHandle.cs @@ -146,11 +146,11 @@ private void Cleanup() // Save last error from P/Invoke in case the implementation of // ReleaseHandle trashes it (important because this ReleaseHandle could // occur implicitly as part of unmarshaling another P/Invoke). - int lastError = Marshal.GetLastWin32Error(); + int lastError = Marshal.GetLastPInvokeError(); ReleaseHandle(); - Marshal.SetLastWin32Error(lastError); + Marshal.SetLastPInvokeError(lastError); GC.SuppressFinalize(this); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index 542f3ba41b19e2..70913553bd7b44 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -1266,5 +1266,10 @@ public static void InitHandle(SafeHandle safeHandle, IntPtr handle) // To help maximize performance of P/Invokes, don't check if safeHandle is null. safeHandle.SetHandle(handle); } + + public static int GetLastWin32Error() + { + return GetLastPInvokeError(); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs index 33c9dcb575ced8..6d1bbf831773a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs @@ -243,9 +243,9 @@ private void InternalRelease(bool disposeOrFinalizeOperation) // Save last error from P/Invoke in case the implementation of ReleaseHandle // trashes it (important because this ReleaseHandle could occur implicitly // as part of unmarshaling another P/Invoke). - int lastError = Marshal.GetLastWin32Error(); + int lastError = Marshal.GetLastPInvokeError(); ReleaseHandle(); - Marshal.SetLastWin32Error(lastError); + Marshal.SetLastPInvokeError(lastError); } } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 5fcb17353156e9..e116175fd3617e 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -570,6 +570,8 @@ public static void FreeHGlobal(System.IntPtr hglobal) { } public static System.IntPtr GetIDispatchForObject(object o) { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public static System.IntPtr GetIUnknownForObject(object o) { throw null; } + public static int GetLastPInvokeError() { throw null; } + public static int GetLastSystemError() { throw null; } public static int GetLastWin32Error() { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -662,6 +664,8 @@ public static void PtrToStructure(System.IntPtr ptr, [System.Diagnostics.Code public static System.IntPtr SecureStringToGlobalAllocUnicode(System.Security.SecureString s) { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public static bool SetComObjectData(object obj, object key, object? data) { throw null; } + public static void SetLastPInvokeError(int error) { throw null; } + public static void SetLastSystemError(int error) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static int SizeOf(object structure) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs index 68bb8fa466a381..433934ec7aa796 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs @@ -11,8 +11,43 @@ namespace System.Runtime.InteropServices { public partial class Marshal { + /// + /// Get the last platform invoke error on the current thread + /// + /// The last platform invoke error + /// + /// The last platform invoke error corresponds to the error set by either the most recent platform + /// invoke that was configured to set the last error or a call to . + /// [MethodImplAttribute(MethodImplOptions.InternalCall)] - public static extern int GetLastWin32Error(); + public static extern int GetLastPInvokeError(); + + /// + /// Set the last platform invoke error on the current thread + /// + /// Error to set + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void SetLastPInvokeError(int error); + + /// + /// Get the last system error on the current thread + /// + /// The last system error + /// + /// The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows) + /// + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern int GetLastSystemError(); + + /// + /// Set the last system error on the current thread + /// + /// Error to set + /// + /// The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows) + /// + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern void SetLastSystemError(int error); [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern void DestroyStructure(IntPtr ptr, Type structuretype); @@ -35,9 +70,6 @@ internal static bool IsPinnable(object? obj) //return !type.IsValueType || RuntimeTypeHandle.HasReferences (type as RuntimeType); } - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern void SetLastWin32Error(int error); - private static void PrelinkCore(MethodInfo m) { if (!(m is RuntimeMethodInfo)) diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index d1b44dc81c4e0c..185a799599a962 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -346,12 +346,14 @@ ICALL_TYPE(MARSHAL, "System.Runtime.InteropServices.Marshal", MARSHAL_4) HANDLES(MARSHAL_4, "DestroyStructure", ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure, void, 2, (gpointer, MonoReflectionType)) HANDLES(MARSHAL_9, "GetDelegateForFunctionPointerInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal, MonoDelegate, 2, (gpointer, MonoReflectionType)) HANDLES(MARSHAL_10, "GetFunctionPointerForDelegateInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal, gpointer, 1, (MonoDelegate)) -NOHANDLES(ICALL(MARSHAL_11, "GetLastWin32Error", ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error)) +NOHANDLES(ICALL(MARSHAL_11, "GetLastPInvokeError", ves_icall_System_Runtime_InteropServices_Marshal_GetLastPInvokeError)) +NOHANDLES(ICALL(MARSHAL_32, "GetLastSystemError", ves_icall_System_Runtime_InteropServices_Marshal_GetLastSystemError)) HANDLES(MARSHAL_48a, "IsPinnableType", ves_icall_System_Runtime_InteropServices_Marshal_IsPinnableType, MonoBoolean, 1, (MonoReflectionType)) HANDLES(MARSHAL_12, "OffsetOf", ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf, int, 2, (MonoReflectionType, MonoString)) HANDLES(MARSHAL_13, "PrelinkInternal", ves_icall_System_Runtime_InteropServices_Marshal_Prelink, void, 1, (MonoReflectionMethod)) HANDLES(MARSHAL_20, "PtrToStructureInternal", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructureInternal, void, 3, (gconstpointer, MonoObject, MonoBoolean)) -NOHANDLES(ICALL(MARSHAL_29a, "SetLastWin32Error", ves_icall_System_Runtime_InteropServices_Marshal_SetLastWin32Error)) +NOHANDLES(ICALL(MARSHAL_29a, "SetLastPInvokeError", ves_icall_System_Runtime_InteropServices_Marshal_SetLastPInvokeError)) +NOHANDLES(ICALL(MARSHAL_33, "SetLastSystemError", ves_icall_System_Runtime_InteropServices_Marshal_SetLastSystemError)) HANDLES(MARSHAL_30, "SizeOf", ves_icall_System_Runtime_InteropServices_Marshal_SizeOf, guint32, 1, (MonoReflectionType)) HANDLES(MARSHAL_31, "SizeOfHelper", ves_icall_System_Runtime_InteropServices_Marshal_SizeOfHelper, guint32, 2, (MonoReflectionType, MonoBoolean)) HANDLES(MARSHAL_34, "StructureToPtr", ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr, void, 3, (MonoObject, gpointer, MonoBoolean)) diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 47d25a99f469dc..c7ea6b536190db 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -4785,19 +4785,39 @@ mono_marshal_clear_last_error (void) #endif } -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void) +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_GetLastPInvokeError (void) { return GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id)); } void -ves_icall_System_Runtime_InteropServices_Marshal_SetLastWin32Error (guint32 err) +ves_icall_System_Runtime_InteropServices_Marshal_SetLastPInvokeError (guint32 err) { mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (err)); } -guint32 +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_GetLastSystemError (void) +{ +#ifdef WIN32 + return GetLastError (); +#else + return errno; +#endif +} + +void +ves_icall_System_Runtime_InteropServices_Marshal_SetLastSystemError (guint32 err) +{ +#ifdef WIN32 + SetLastError (err); +#else + errno = err; +#endif +} + +guint32 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype, MonoError *error) { if (MONO_HANDLE_IS_NULL (rtype)) { diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index ea3408748be47d..bb02f54217e299 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -611,12 +611,20 @@ gpointer mono_marshal_lookup_pinvoke (MonoMethod *method); ICALL_EXPORT -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void); +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_GetLastPInvokeError (void); ICALL_EXPORT void -ves_icall_System_Runtime_InteropServices_Marshal_SetLastWin32Error (guint32 err); +ves_icall_System_Runtime_InteropServices_Marshal_SetLastPInvokeError (guint32 err); + +ICALL_EXPORT +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_GetLastSystemError (void); + +ICALL_EXPORT +void +ves_icall_System_Runtime_InteropServices_Marshal_SetLastSystemError (guint32 err); ICALL_EXPORT mono_bstr From 0c87b33929bd66b282dd1048b83caf153cde3902 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 16 Apr 2021 18:47:13 -0700 Subject: [PATCH 2/8] Add libraries tests --- ...ystem.Runtime.InteropServices.Tests.csproj | 1 + .../InteropServices/Marshal/LastErrorTests.cs | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/LastErrorTests.cs diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj index e7d065da06ceae..79c9de91710d26 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj @@ -96,6 +96,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/LastErrorTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/LastErrorTests.cs new file mode 100644 index 00000000000000..e16110f1a07a42 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/LastErrorTests.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Runtime.InteropServices.Tests +{ + public class LastErrorTests + { + [Fact] + public void LastPInvokeError_RoundTrip() + { + int errorExpected = 123; + Marshal.SetLastPInvokeError(errorExpected); + Assert.Equal(errorExpected, Marshal.GetLastPInvokeError()); + } + + [Fact] + public void LastSystemError_RoundTrip() + { + int errorExpected = 123; + Marshal.SetLastSystemError(errorExpected); + Assert.Equal(errorExpected, Marshal.GetLastSystemError()); + } + + [Fact] + public void SetLastPInvokeError_GetLastWin32Error() + { + int errorExpected = 123; + Marshal.SetLastPInvokeError(errorExpected); + Assert.Equal(errorExpected, Marshal.GetLastWin32Error()); + } + + [Fact] + public void SetLastSystemError_PInvokeErrorUnchanged() + { + int pinvokeError = 123; + Marshal.SetLastPInvokeError(pinvokeError); + + int systemError = pinvokeError + 1; + Marshal.SetLastSystemError(systemError); + + // Setting last system error should not affect the last P/Invoke error + int pinvokeActual = Marshal.GetLastPInvokeError(); + Assert.NotEqual(systemError, pinvokeActual); + Assert.Equal(pinvokeError, pinvokeActual); + + int win32Actual = Marshal.GetLastWin32Error(); + Assert.NotEqual(systemError, win32Actual); + Assert.Equal(pinvokeError, win32Actual); + } + } +} From 90727983b23f83291edee8ed6d2316763ffb8e27 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 19 Apr 2021 10:32:57 -0700 Subject: [PATCH 3/8] Add SetLastError P/Invoke tests --- src/tests/Interop/CMakeLists.txt | 1 + .../PInvoke/SetLastError/CMakeLists.txt | 10 +++ .../SetLastError/SetLastErrorNative.cpp | 16 ++++ .../PInvoke/SetLastError/SetLastErrorTest.cs | 79 +++++++++++++++++++ .../SetLastError/SetLastErrorTest.csproj | 12 +++ 5 files changed, 118 insertions(+) create mode 100644 src/tests/Interop/PInvoke/SetLastError/CMakeLists.txt create mode 100644 src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp create mode 100644 src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs create mode 100644 src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.csproj diff --git a/src/tests/Interop/CMakeLists.txt b/src/tests/Interop/CMakeLists.txt index a39791f73c21f5..8622b4f4da4b26 100644 --- a/src/tests/Interop/CMakeLists.txt +++ b/src/tests/Interop/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(PInvoke/Delegate) add_subdirectory(PInvoke/Primitives/Int) add_subdirectory(PInvoke/Primitives/RuntimeHandles) add_subdirectory(PInvoke/Primitives/Pointer) +add_subdirectory(PInvoke/SetLastError) add_subdirectory(PInvoke/SizeParamIndex/PInvoke/PassingByOut) add_subdirectory(PInvoke/SizeParamIndex/PInvoke/PassingByRef) add_subdirectory(PInvoke/SizeParamIndex/ReversePInvoke/PassingByOut) diff --git a/src/tests/Interop/PInvoke/SetLastError/CMakeLists.txt b/src/tests/Interop/PInvoke/SetLastError/CMakeLists.txt new file mode 100644 index 00000000000000..4a0cae2e12ca0e --- /dev/null +++ b/src/tests/Interop/PInvoke/SetLastError/CMakeLists.txt @@ -0,0 +1,10 @@ +project(SetLastErrorNative) +include("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +set(SOURCES SetLastErrorNative.cpp) + +# add the shared library +add_library(SetLastErrorNative SHARED ${SOURCES}) +target_link_libraries(SetLastErrorNative ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install(TARGETS SetLastErrorNative DESTINATION bin) diff --git a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp new file mode 100644 index 00000000000000..b21da0a52103c3 --- /dev/null +++ b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include + +extern "C" DLL_EXPORT void STDMETHODCALLTYPE SetError(int err, bool shouldSetError) +{ + if (!shouldSetError) + return; + +#ifdef WINDOWS + ::SetLastError(err); +#else + errno = err; +#endif +} diff --git a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs new file mode 100644 index 00000000000000..67e8b8c25bedd8 --- /dev/null +++ b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using TestLibrary; + +class SetLastErrorTest +{ + private static class SetLastErrorNative + { + private const string SetError = nameof(SetError); + + [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError)] + public static extern int SetError_Default(int error, byte shouldSetError); + + [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError, SetLastError = false)] + public static extern int SetError_False(int error, byte shouldSetError); + + [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError, SetLastError = true)] + public static extern int SetError_True(int error, byte shouldSetError); + } + + public static void LastErrorHasExpectedValue() + { + // Default (same behaviour as SetLastError=false) + { + int expected = Marshal.GetLastPInvokeError(); + SetLastErrorNative.SetError_Default(expected + 1, shouldSetError: 1); + int actual = Marshal.GetLastPInvokeError(); + Assert.AreEqual(expected, actual); + } + + // SetLastError=false + { + int expected = Marshal.GetLastPInvokeError(); + SetLastErrorNative.SetError_False(expected + 1, shouldSetError: 1); + int actual = Marshal.GetLastPInvokeError(); + Assert.AreEqual(expected, actual); + } + + // SetLastError=true + { + int expected = Marshal.GetLastPInvokeError(); + expected++; + SetLastErrorNative.SetError_True(expected, shouldSetError: 1); + int actual = Marshal.GetLastPInvokeError(); + Assert.AreEqual(expected, actual); + } + } + + public static void ClearPreviousError() + { + // Set the last P/Invoke error to non-zero + int error = 100; + Marshal.SetLastPInvokeError(0); + + // Don't actually set the error in the native call. SetLastError=true should clear any existing error. + SetLastErrorNative.SetError_True(error, shouldSetError: 0); + int actual = Marshal.GetLastPInvokeError(); + Assert.AreEqual(0, actual); + } + + static int Main(string[] args) + { + try + { + LastErrorHasExpectedValue(); + ClearPreviousError(); + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } +} diff --git a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.csproj b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.csproj new file mode 100644 index 00000000000000..38fdf93e5a0cef --- /dev/null +++ b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.csproj @@ -0,0 +1,12 @@ + + + Exe + + + + + + + + + From b83d43e970cf6a2291eb8a78a837b46907865f6e Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 19 Apr 2021 13:26:29 -0700 Subject: [PATCH 4/8] Put Get/SetLastSystemError in shared CoreLib --- .../InteropServices/Marshal.CoreCLR.cs | 24 ++----------------- src/coreclr/vm/ecalllist.h | 2 -- src/coreclr/vm/marshalnative.cpp | 16 ------------- src/coreclr/vm/marshalnative.h | 2 -- .../Unix/System.Native/Interop.ErrNo.cs | 19 +++++++++++++++ .../Windows/Kernel32/Interop.SetLastError.cs | 14 +++++++++++ .../Native/Unix/System.Native/pal_errno.c | 10 ++++++++ .../Native/Unix/System.Native/pal_errno.h | 10 ++++++++ .../System.Private.CoreLib.Shared.projitems | 12 +++++++--- .../Runtime/InteropServices/Marshal.Unix.cs | 24 +++++++++++++++++++ .../InteropServices/Marshal.Windows.cs | 24 +++++++++++++++++++ .../Runtime/InteropServices/Marshal.Mono.cs | 20 ---------------- src/mono/mono/metadata/icall-def-netcore.h | 2 -- src/mono/mono/metadata/marshal.c | 20 ---------------- src/mono/mono/metadata/marshal.h | 8 ------- 15 files changed, 112 insertions(+), 95 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Unix/System.Native/Interop.ErrNo.cs create mode 100644 src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetLastError.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs index 99ab0fd9c07ee9..77bd01b4bd3d4f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs @@ -181,26 +181,6 @@ private static unsafe void WriteValueSlow(object ptr, int ofs, T val, Action< [MethodImpl(MethodImplOptions.InternalCall)] public static extern void SetLastPInvokeError(int error); - /// - /// Get the last system error on the current thread - /// - /// The last system error - /// - /// The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows) - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern int GetLastSystemError(); - - /// - /// Set the last system error on the current thread - /// - /// Error to set - /// - /// The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows) - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void SetLastSystemError(int error); - private static void PrelinkCore(MethodInfo m) { if (!(m is RuntimeMethodInfo rmi)) @@ -253,7 +233,7 @@ private static object PtrToStructureHelper(IntPtr ptr, Type structureType) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool IsPinnable(object? obj); -#if TARGET_WINDOWS +#if FEATURE_COMINTEROP /// /// Returns the HInstance for this module. Returns -1 if the module doesn't have /// an HInstance. In Memory (Dynamic) Modules won't have an HInstance. @@ -276,7 +256,7 @@ public static IntPtr GetHINSTANCE(Module m) [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] private static extern IntPtr GetHINSTANCE(QCallModule m); -#endif // TARGET_WINDOWS +#endif // FEATURE_COMINTEROP [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 2655205a2751ea..8478635d24487d 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -744,8 +744,6 @@ FCFuncEnd() FCFuncStart(gInteropMarshalFuncs) FCFuncElement("GetLastPInvokeError", MarshalNative::GetLastPInvokeError) FCFuncElement("SetLastPInvokeError", MarshalNative::SetLastPInvokeError) - FCFuncElement("GetLastSystemError", MarshalNative::GetLastSystemError) - FCFuncElement("SetLastSystemError", MarshalNative::SetLastSystemError) FCFuncElement("SizeOfHelper", MarshalNative::SizeOfClass) FCFuncElement("StructureToPtr", MarshalNative::StructureToPtr) FCFuncElement("PtrToStructureHelper", MarshalNative::PtrToStructureHelper) diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp index f0d47cb1030ac2..7100fe37d8b396 100644 --- a/src/coreclr/vm/marshalnative.cpp +++ b/src/coreclr/vm/marshalnative.cpp @@ -415,7 +415,6 @@ FCIMPL0(int, MarshalNative::GetLastPInvokeError) } FCIMPLEND - /************************************************************************ * Marshal.SetLastPInvokeError */ @@ -427,21 +426,6 @@ FCIMPL1(void, MarshalNative::SetLastPInvokeError, int error) } FCIMPLEND -FCIMPL0(int, MarshalNative::GetLastSystemError) -{ - FCALL_CONTRACT; - return ::GetLastError(); -} -FCIMPLEND - -FCIMPL1(void, MarshalNative::SetLastSystemError, int error) -{ - FCALL_CONTRACT; - ::SetLastError(error); -} -FCIMPLEND - - /************************************************************************ * Support for the GCHandle class. */ diff --git a/src/coreclr/vm/marshalnative.h b/src/coreclr/vm/marshalnative.h index 51ff113d4c32fb..fea67622219c72 100644 --- a/src/coreclr/vm/marshalnative.h +++ b/src/coreclr/vm/marshalnative.h @@ -32,8 +32,6 @@ class MarshalNative static FCDECL1(UINT32, OffsetOfHelper, ReflectFieldObject* pFieldUNSAFE); static FCDECL0(int, GetLastPInvokeError); static FCDECL1(void, SetLastPInvokeError, int error); - static FCDECL0(int, GetLastSystemError); - static FCDECL1(void, SetLastSystemError, int error); static FCDECL3(VOID, StructureToPtr, Object* pObjUNSAFE, LPVOID ptr, CLR_BOOL fDeleteOld); static FCDECL3(VOID, PtrToStructureHelper, LPVOID ptr, Object* pObjIn, CLR_BOOL allowValueClasses); diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.ErrNo.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.ErrNo.cs new file mode 100644 index 00000000000000..3e321d512635a4 --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.ErrNo.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal unsafe partial class Sys + { + [DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetErrNo")] + [SuppressGCTransition] + internal static extern int GetErrNo(); + + [DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_SetErrNo")] + [SuppressGCTransition] + internal static extern void SetErrNo(int errorCode); + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetLastError.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetLastError.cs new file mode 100644 index 00000000000000..1a4394800ce99b --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetLastError.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + [SuppressGCTransition] + internal static extern void SetLastError(int errorCode); + } +} diff --git a/src/libraries/Native/Unix/System.Native/pal_errno.c b/src/libraries/Native/Unix/System.Native/pal_errno.c index 89b6e5bac6617f..4920a5442ec617 100644 --- a/src/libraries/Native/Unix/System.Native/pal_errno.c +++ b/src/libraries/Native/Unix/System.Native/pal_errno.c @@ -17,3 +17,13 @@ const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t { return StrErrorR(platformErrno, buffer, bufferSize); } + +int32_t SystemNative_GetErrNo(void) +{ + return errno; +} + +void SystemNative_SetErrNo(int32_t errorCode) +{ + errno = errorCode; +} diff --git a/src/libraries/Native/Unix/System.Native/pal_errno.h b/src/libraries/Native/Unix/System.Native/pal_errno.h index d256052add6f28..8c5f9c9aa70d71 100644 --- a/src/libraries/Native/Unix/System.Native/pal_errno.h +++ b/src/libraries/Native/Unix/System.Native/pal_errno.h @@ -42,3 +42,13 @@ PALEXPORT int32_t SystemNative_ConvertErrorPalToPlatform(int32_t error); * as possible and null-terminated. */ PALEXPORT const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize); + +/** + * Gets the current errno value + */ +PALEXPORT int32_t SystemNative_GetErrNo(void); + +/** + * Sets the errno value + */ +PALEXPORT void SystemNative_SetErrNo(int32_t errorCode); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index a2bb38f63185c0..d406f36c32c487 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1387,6 +1387,9 @@ Common\Interop\Windows\Kernel32\Interop.GenericOperations.cs + + Common\Interop\Windows\Kernel32\Interop.GetLastError.cs + Common\Interop\Windows\Kernel32\Interop.GET_FILEEX_INFO_LEVELS.cs @@ -1525,6 +1528,9 @@ Common\Interop\Windows\Kernel32\Interop.SetFilePointerEx.cs + + Common\Interop\Windows\Kernel32\Interop.SetLastError.cs + Common\Interop\Windows\Kernel32\Interop.SetThreadErrorMode.cs @@ -1743,6 +1749,9 @@ Common\Interop\Unix\System.Native\Interop.Close.cs + + Common\Interop\Unix\System.Native\Interop.ErrNo.cs + Common\Interop\Unix\System.Native\Interop.FLock.cs @@ -2021,9 +2030,6 @@ - - Interop\Windows\Kernel32\Interop.GetLastError.cs - Interop\Windows\Kernel32\Interop.Threading.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs index f8af59eeae8651..08ab87a390fffc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs @@ -200,5 +200,29 @@ public static unsafe void FreeBSTR(IntPtr ptr) return null; } + + /// + /// Get the last system error on the current thread + /// + /// The last system error + /// + /// The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows) + /// + public static int GetLastSystemError() + { + return Interop.Sys.GetErrNo(); + } + + /// + /// Set the last system error on the current thread + /// + /// Error to set + /// + /// The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows) + /// + public static void SetLastSystemError(int error) + { + Interop.Sys.SetErrNo(error); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs index 6df77c5c6dbdb8..b7f4c11f7ccb42 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs @@ -233,5 +233,29 @@ public static void FreeBSTR(IntPtr ptr) return GetTypeFromCLSID(clsid, server, throwOnError); } + + /// + /// Get the last system error on the current thread + /// + /// The last system error + /// + /// The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows) + /// + public static int GetLastSystemError() + { + return Interop.Kernel32.GetLastError(); + } + + /// + /// Set the last system error on the current thread + /// + /// Error to set + /// + /// The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows) + /// + public static void SetLastSystemError(int error) + { + Interop.Kernel32.SetLastError(error); + } } } diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs index 433934ec7aa796..6e712350cb5adb 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs @@ -29,26 +29,6 @@ public partial class Marshal [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern void SetLastPInvokeError(int error); - /// - /// Get the last system error on the current thread - /// - /// The last system error - /// - /// The error is that for the current operating system (e.g. errno on Unix, GetLastError on Windows) - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern int GetLastSystemError(); - - /// - /// Set the last system error on the current thread - /// - /// Error to set - /// - /// The error is that for the current operating system (e.g. errno on Unix, SetLastError on Windows) - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void SetLastSystemError(int error); - [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern void DestroyStructure(IntPtr ptr, Type structuretype); diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 185a799599a962..c51e5e680d1f23 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -347,13 +347,11 @@ HANDLES(MARSHAL_4, "DestroyStructure", ves_icall_System_Runtime_InteropServices_ HANDLES(MARSHAL_9, "GetDelegateForFunctionPointerInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal, MonoDelegate, 2, (gpointer, MonoReflectionType)) HANDLES(MARSHAL_10, "GetFunctionPointerForDelegateInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal, gpointer, 1, (MonoDelegate)) NOHANDLES(ICALL(MARSHAL_11, "GetLastPInvokeError", ves_icall_System_Runtime_InteropServices_Marshal_GetLastPInvokeError)) -NOHANDLES(ICALL(MARSHAL_32, "GetLastSystemError", ves_icall_System_Runtime_InteropServices_Marshal_GetLastSystemError)) HANDLES(MARSHAL_48a, "IsPinnableType", ves_icall_System_Runtime_InteropServices_Marshal_IsPinnableType, MonoBoolean, 1, (MonoReflectionType)) HANDLES(MARSHAL_12, "OffsetOf", ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf, int, 2, (MonoReflectionType, MonoString)) HANDLES(MARSHAL_13, "PrelinkInternal", ves_icall_System_Runtime_InteropServices_Marshal_Prelink, void, 1, (MonoReflectionMethod)) HANDLES(MARSHAL_20, "PtrToStructureInternal", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructureInternal, void, 3, (gconstpointer, MonoObject, MonoBoolean)) NOHANDLES(ICALL(MARSHAL_29a, "SetLastPInvokeError", ves_icall_System_Runtime_InteropServices_Marshal_SetLastPInvokeError)) -NOHANDLES(ICALL(MARSHAL_33, "SetLastSystemError", ves_icall_System_Runtime_InteropServices_Marshal_SetLastSystemError)) HANDLES(MARSHAL_30, "SizeOf", ves_icall_System_Runtime_InteropServices_Marshal_SizeOf, guint32, 1, (MonoReflectionType)) HANDLES(MARSHAL_31, "SizeOfHelper", ves_icall_System_Runtime_InteropServices_Marshal_SizeOfHelper, guint32, 2, (MonoReflectionType, MonoBoolean)) HANDLES(MARSHAL_34, "StructureToPtr", ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr, void, 3, (MonoObject, gpointer, MonoBoolean)) diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index c7ea6b536190db..06d58ea7d9f87c 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -4797,26 +4797,6 @@ ves_icall_System_Runtime_InteropServices_Marshal_SetLastPInvokeError (guint32 er mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (err)); } -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_GetLastSystemError (void) -{ -#ifdef WIN32 - return GetLastError (); -#else - return errno; -#endif -} - -void -ves_icall_System_Runtime_InteropServices_Marshal_SetLastSystemError (guint32 err) -{ -#ifdef WIN32 - SetLastError (err); -#else - errno = err; -#endif -} - guint32 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype, MonoError *error) { diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index bb02f54217e299..ee94b8e6bfa182 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -618,14 +618,6 @@ ICALL_EXPORT void ves_icall_System_Runtime_InteropServices_Marshal_SetLastPInvokeError (guint32 err); -ICALL_EXPORT -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_GetLastSystemError (void); - -ICALL_EXPORT -void -ves_icall_System_Runtime_InteropServices_Marshal_SetLastSystemError (guint32 err); - ICALL_EXPORT mono_bstr ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2 *ptr, int len); From 312875e71fc4086d78c649633f78488750ab9174 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 19 Apr 2021 13:26:49 -0700 Subject: [PATCH 5/8] Fix build on Unix --- src/libraries/Native/Unix/System.Native/entrypoints.c | 2 ++ src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/libraries/Native/Unix/System.Native/entrypoints.c b/src/libraries/Native/Unix/System.Native/entrypoints.c index 53e30315ea0c19..a8be7305be7a93 100644 --- a/src/libraries/Native/Unix/System.Native/entrypoints.c +++ b/src/libraries/Native/Unix/System.Native/entrypoints.c @@ -239,6 +239,8 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_CreateAutoreleasePool) DllImportEntry(SystemNative_DrainAutoreleasePool) DllImportEntry(SystemNative_iOSSupportVersion) + DllImportEntry(SystemNative_GetErrNo) + DllImportEntry(SystemNative_SetErrNo) }; EXTERN_C const void* SystemResolveDllImport(const char* name); diff --git a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp index b21da0a52103c3..e85413102a79bb 100644 --- a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp +++ b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorNative.cpp @@ -3,6 +3,10 @@ #include +#ifndef WINDOWS +#include +#endif + extern "C" DLL_EXPORT void STDMETHODCALLTYPE SetError(int err, bool shouldSetError) { if (!shouldSetError) From d4307b6e7df201eef9829c113559ea3feec5ecbb Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 20 Apr 2021 00:15:08 -0700 Subject: [PATCH 6/8] Fix Test --- .../Interop/PInvoke/SetLastError/SetLastErrorTest.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs index 67e8b8c25bedd8..b76465a27607e8 100644 --- a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs +++ b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs @@ -12,13 +12,13 @@ private static class SetLastErrorNative private const string SetError = nameof(SetError); [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError)] - public static extern int SetError_Default(int error, byte shouldSetError); + public static extern void SetError_Default(int error, byte shouldSetError); [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError, SetLastError = false)] - public static extern int SetError_False(int error, byte shouldSetError); + public static extern void SetError_False(int error, byte shouldSetError); [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError, SetLastError = true)] - public static extern int SetError_True(int error, byte shouldSetError); + public static extern void SetError_True(int error, byte shouldSetError); } public static void LastErrorHasExpectedValue() @@ -53,9 +53,10 @@ public static void ClearPreviousError() { // Set the last P/Invoke error to non-zero int error = 100; - Marshal.SetLastPInvokeError(0); + Marshal.SetLastPInvokeError(error); - // Don't actually set the error in the native call. SetLastError=true should clear any existing error. + // Don't actually set the error in the native call. + // Calling a P/Invoke with SetLastError=true should clear any existing error. SetLastErrorNative.SetError_True(error, shouldSetError: 0); int actual = Marshal.GetLastPInvokeError(); Assert.AreEqual(0, actual); From fec0fc720f168a2a5fef2867f1bc75f0af491dff Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 20 Apr 2021 16:37:04 -0700 Subject: [PATCH 7/8] Disable SetLastError p/invoke test on mono --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index b575a39cc9caea..0050dc3e563bc2 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1296,6 +1296,9 @@ https://github.com/dotnet/runtime/issues/48084 + + https://github.com/dotnet/runtime/issues/51600 + needs triage From 65f24adfe4aa65ef6cd6a7a7a137e622a23996a0 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 21 Apr 2021 14:29:52 -0700 Subject: [PATCH 8/8] PR feedback --- .../PInvoke/SetLastError/SetLastErrorTest.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs index b76465a27607e8..d607ebd191b7d8 100644 --- a/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs +++ b/src/tests/Interop/PInvoke/SetLastError/SetLastErrorTest.cs @@ -12,13 +12,13 @@ private static class SetLastErrorNative private const string SetError = nameof(SetError); [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError)] - public static extern void SetError_Default(int error, byte shouldSetError); + public static extern void SetError_Default(int error, [MarshalAs(UnmanagedType.U1)] bool shouldSetError); [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError, SetLastError = false)] - public static extern void SetError_False(int error, byte shouldSetError); + public static extern void SetError_False(int error, [MarshalAs(UnmanagedType.U1)] bool shouldSetError); [DllImport(nameof(SetLastErrorNative), EntryPoint = SetError, SetLastError = true)] - public static extern void SetError_True(int error, byte shouldSetError); + public static extern void SetError_True(int error, [MarshalAs(UnmanagedType.U1)] bool shouldSetError); } public static void LastErrorHasExpectedValue() @@ -26,7 +26,7 @@ public static void LastErrorHasExpectedValue() // Default (same behaviour as SetLastError=false) { int expected = Marshal.GetLastPInvokeError(); - SetLastErrorNative.SetError_Default(expected + 1, shouldSetError: 1); + SetLastErrorNative.SetError_Default(expected + 1, shouldSetError: true); int actual = Marshal.GetLastPInvokeError(); Assert.AreEqual(expected, actual); } @@ -34,7 +34,7 @@ public static void LastErrorHasExpectedValue() // SetLastError=false { int expected = Marshal.GetLastPInvokeError(); - SetLastErrorNative.SetError_False(expected + 1, shouldSetError: 1); + SetLastErrorNative.SetError_False(expected + 1, shouldSetError: true); int actual = Marshal.GetLastPInvokeError(); Assert.AreEqual(expected, actual); } @@ -43,7 +43,7 @@ public static void LastErrorHasExpectedValue() { int expected = Marshal.GetLastPInvokeError(); expected++; - SetLastErrorNative.SetError_True(expected, shouldSetError: 1); + SetLastErrorNative.SetError_True(expected, shouldSetError: true); int actual = Marshal.GetLastPInvokeError(); Assert.AreEqual(expected, actual); } @@ -57,7 +57,7 @@ public static void ClearPreviousError() // Don't actually set the error in the native call. // Calling a P/Invoke with SetLastError=true should clear any existing error. - SetLastErrorNative.SetError_True(error, shouldSetError: 0); + SetLastErrorNative.SetError_True(error, shouldSetError: false); int actual = Marshal.GetLastPInvokeError(); Assert.AreEqual(0, actual); }