From 9c1c0331da0163ce4b9da86634c65362270387f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 03:36:38 +0000 Subject: [PATCH 1/8] Initial plan From 51a9274b5bb580d93e085f30d58c725cb33c298a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 03:59:01 +0000 Subject: [PATCH 2/8] Unify SECURITY_ATTRIBUTES code from FileSystemAclExtensions and SafeFileHandle Co-authored-by: danmoseley <6385855+danmoseley@users.noreply.github.com> --- .../Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs | 8 ++++++++ .../src/System/IO/FileSystemAclExtensions.cs | 6 +----- .../Win32/SafeHandles/SafeFileHandle.Windows.cs | 10 +--------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs index f390490f3a5848..ab67c7eb580831 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.IO; using System.Runtime.InteropServices; internal static partial class Interop @@ -14,6 +15,13 @@ internal struct SECURITY_ATTRIBUTES internal uint nLength; internal unsafe void* lpSecurityDescriptor; internal BOOL bInheritHandle; + + internal static unsafe SECURITY_ATTRIBUTES Create(FileShare share) => + new SECURITY_ATTRIBUTES + { + nLength = (uint)sizeof(SECURITY_ATTRIBUTES), + bInheritHandle = ((share & FileShare.Inheritable) != 0) ? BOOL.TRUE : BOOL.FALSE + }; } } } diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs index 7c13c2efeb820b..0ced5282467074 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs +++ b/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs @@ -269,11 +269,7 @@ private static unsafe SafeFileHandle CreateFileHandle(string fullPath, FileMode SafeFileHandle handle; - var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - bInheritHandle = ((share & FileShare.Inheritable) != 0) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, - }; + var secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(share); if (security != null) { diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index 3d5f8d22db02ba..088fb74dba577a 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -131,15 +131,7 @@ internal static SafeFileHandle Open(string fullPath, FileMode mode, FileAccess a private static unsafe SafeFileHandle CreateFile(string fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default; - if ((share & FileShare.Inheritable) != 0) - { - secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - bInheritHandle = Interop.BOOL.TRUE - }; - } + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(share); int fAccess = ((access & FileAccess.Read) == FileAccess.Read ? Interop.Kernel32.GenericOperations.GENERIC_READ : 0) | From a3650af1eb75821dd14d49ff1e6469f9c2c5a574 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 05:07:37 +0000 Subject: [PATCH 3/8] Address review feedback: use Create(bool) factory, apply to all SECURITY_ATTRIBUTES instances Co-authored-by: danmoseley <6385855+danmoseley@users.noreply.github.com> --- .../Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs | 11 ++++++++--- .../IO/FileSystem.DirectoryCreation.Windows.cs | 7 ++----- .../src/Microsoft/Win32/RegistryKey.cs | 8 ++------ .../src/System/IO/FileSystemAclExtensions.cs | 2 +- .../MemoryMappedFiles/MemoryMappedFile.Windows.cs | 13 ++----------- .../src/System/IO/Pipes/PipeStream.Windows.cs | 12 ++---------- .../Win32/SafeHandles/SafeFileHandle.Windows.cs | 2 +- .../src/System/Threading/EventWaitHandle.Windows.cs | 2 +- .../src/System/Threading/Mutex.Windows.cs | 2 +- .../src/System/Threading/Semaphore.Windows.cs | 2 +- .../src/System/Threading/EventWaitHandleAcl.cs | 7 ++----- .../src/System/Threading/MutexAcl.cs | 7 ++----- .../src/System/Threading/SemaphoreAcl.cs | 7 ++----- 13 files changed, 27 insertions(+), 55 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs index ab67c7eb580831..717db004ea319b 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.IO; using System.Runtime.InteropServices; internal static partial class Interop @@ -16,11 +15,17 @@ internal struct SECURITY_ATTRIBUTES internal unsafe void* lpSecurityDescriptor; internal BOOL bInheritHandle; - internal static unsafe SECURITY_ATTRIBUTES Create(FileShare share) => + internal static unsafe SECURITY_ATTRIBUTES Create() => + new SECURITY_ATTRIBUTES + { + nLength = (uint)sizeof(SECURITY_ATTRIBUTES) + }; + + internal static unsafe SECURITY_ATTRIBUTES Create(bool inheritable) => new SECURITY_ATTRIBUTES { nLength = (uint)sizeof(SECURITY_ATTRIBUTES), - bInheritHandle = ((share & FileShare.Inheritable) != 0) ? BOOL.TRUE : BOOL.FALSE + bInheritHandle = inheritable ? BOOL.TRUE : BOOL.FALSE }; } } diff --git a/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs b/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs index dc26d7638964a9..3d09f196608d06 100644 --- a/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs +++ b/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs @@ -77,11 +77,8 @@ public static unsafe void CreateDirectory(string fullPath, byte[]? securityDescr fixed (byte* pSecurityDescriptor = securityDescriptor) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - lpSecurityDescriptor = pSecurityDescriptor - }; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); + secAttrs.lpSecurityDescriptor = pSecurityDescriptor; while (stackDir.Count > 0) { diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs index 0c622e950a8b1f..41155b164fbebd 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs @@ -215,18 +215,14 @@ public unsafe RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck } } - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); byte[]? securityDescriptor = registrySecurity?.GetSecurityDescriptorBinaryForm(); fixed (void* pSecurityDescriptor = securityDescriptor) { if (pSecurityDescriptor is not null) { - secAttrs = new() - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - lpSecurityDescriptor = pSecurityDescriptor - }; + secAttrs.lpSecurityDescriptor = pSecurityDescriptor; } // By default, the new key will be writable. diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs index 0ced5282467074..7fd33e7bf0bfa3 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs +++ b/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs @@ -269,7 +269,7 @@ private static unsafe SafeFileHandle CreateFileHandle(string fullPath, FileMode SafeFileHandle handle; - var secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(share); + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((share & FileShare.Inheritable) != 0); if (security != null) { diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs index 2b1dc6e4651031..c35d4ea8394d72 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs @@ -254,16 +254,7 @@ private static SafeMemoryMappedFileHandle OpenCore( /// Helper method used to extract the native binary security descriptor from the MemoryMappedFileSecurity /// type. If pinningHandle is not null, caller must free it AFTER the call to CreateFile has returned. /// - private static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability) - { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES); - if ((inheritability & HandleInheritability.Inheritable) != 0) - { - secAttrs = default; - secAttrs.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES); - secAttrs.bInheritHandle = Interop.BOOL.TRUE; - } - return secAttrs; - } + private static Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability) => + Interop.Kernel32.SECURITY_ATTRIBUTES.Create((inheritability & HandleInheritability.Inheritable) != 0); } } diff --git a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs index ddff733119a7a8..c7aaf4b8fba2eb 100644 --- a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs +++ b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs @@ -581,16 +581,8 @@ public virtual PipeTransmissionMode ReadMode } } - internal static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability) - { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - bInheritHandle = ((inheritability & HandleInheritability.Inheritable) != 0) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE - }; - - return secAttrs; - } + internal static Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability) => + Interop.Kernel32.SECURITY_ATTRIBUTES.Create((inheritability & HandleInheritability.Inheritable) != 0); internal static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability, PipeSecurity? pipeSecurity, ref GCHandle pinningHandle) { diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index 088fb74dba577a..ec41af86829f68 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -131,7 +131,7 @@ internal static SafeFileHandle Open(string fullPath, FileMode mode, FileAccess a private static unsafe SafeFileHandle CreateFile(string fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(share); + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((share & FileShare.Inheritable) != 0); int fAccess = ((access & FileAccess.Read) == FileAccess.Read ? Interop.Kernel32.GenericOperations.GENERIC_READ : 0) | diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs index 56ca5a68836e33..a2d76c604a25d6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs @@ -58,7 +58,7 @@ private unsafe void CreateEventCore( if (options.CurrentUserOnly) { securityDescriptorInfo = new(CurrentUserOnlyAceRights); - securityAttributes.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES); + securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); securityAttributes.lpSecurityDescriptor = (void*)securityDescriptorInfo.SecurityDescriptor; securityAttributesPtr = &securityAttributes; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs index be9969806a49f8..74a9a3ef4bcb57 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs @@ -48,7 +48,7 @@ private unsafe void CreateMutexCore( if (options.CurrentUserOnly) { securityDescriptorInfo = new(CurrentUserOnlyAceRights); - securityAttributes.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES); + securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); securityAttributes.lpSecurityDescriptor = (void*)securityDescriptorInfo.SecurityDescriptor; securityAttributesPtr = &securityAttributes; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs index a188850a54387d..ab597e1b08b3d1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs @@ -62,7 +62,7 @@ private unsafe void CreateSemaphoreCore( if (options.CurrentUserOnly) { securityDescriptorInfo = new(CurrentUserOnlyAceRights); - securityAttributes.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES); + securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); securityAttributes.lpSecurityDescriptor = (void*)securityDescriptorInfo.SecurityDescriptor; securityAttributesPtr = &securityAttributes; } diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs index 7db2afe4e8f804..4e43d709a51c81 100644 --- a/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs +++ b/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs @@ -46,11 +46,8 @@ public static unsafe EventWaitHandle Create(bool initialState, EventResetMode mo fixed (byte* pSecurityDescriptor = eventSecurity.GetSecurityDescriptorBinaryForm()) { - var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - lpSecurityDescriptor = pSecurityDescriptor - }; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); + secAttrs.lpSecurityDescriptor = pSecurityDescriptor; SafeWaitHandle handle = Interop.Kernel32.CreateEventEx( (IntPtr)(&secAttrs), diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs index 4185c032b1421a..13aaef9f46eb93 100644 --- a/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs +++ b/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs @@ -31,11 +31,8 @@ public static unsafe Mutex Create(bool initiallyOwned, string? name, out bool cr fixed (byte* pSecurityDescriptor = mutexSecurity.GetSecurityDescriptorBinaryForm()) { - var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - lpSecurityDescriptor = pSecurityDescriptor - }; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); + secAttrs.lpSecurityDescriptor = pSecurityDescriptor; SafeWaitHandle handle = Interop.Kernel32.CreateMutexEx( (IntPtr)(&secAttrs), diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs index 1235e6594a72d1..db7c400474dc65 100644 --- a/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs +++ b/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs @@ -48,11 +48,8 @@ public static unsafe Semaphore Create(int initialCount, int maximumCount, string fixed (byte* pSecurityDescriptor = semaphoreSecurity.GetSecurityDescriptorBinaryForm()) { - var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES - { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - lpSecurityDescriptor = pSecurityDescriptor - }; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); + secAttrs.lpSecurityDescriptor = pSecurityDescriptor; SafeWaitHandle handle = Interop.Kernel32.CreateSemaphoreEx( (IntPtr)(&secAttrs), From 3062a3312a0f0ff35c830271b2524e9516b17a18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 06:10:24 +0000 Subject: [PATCH 4/8] Add Create(void* lpSecurityDescriptor) overload, fold lpSecurityDescriptor into factory calls Co-authored-by: danmoseley <6385855+danmoseley@users.noreply.github.com> --- .../Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs | 8 +++++++- .../src/System/IO/FileSystem.DirectoryCreation.Windows.cs | 3 +-- .../src/Microsoft/Win32/RegistryKey.cs | 8 +++----- .../src/System/Threading/EventWaitHandle.Windows.cs | 3 +-- .../src/System/Threading/Mutex.Windows.cs | 3 +-- .../src/System/Threading/Semaphore.Windows.cs | 3 +-- .../src/System/Threading/EventWaitHandleAcl.cs | 3 +-- .../src/System/Threading/MutexAcl.cs | 3 +-- .../src/System/Threading/SemaphoreAcl.cs | 3 +-- 9 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs index 717db004ea319b..248657a6ac1dcc 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs @@ -1,7 +1,6 @@ // 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 @@ -21,6 +20,13 @@ internal static unsafe SECURITY_ATTRIBUTES Create() => nLength = (uint)sizeof(SECURITY_ATTRIBUTES) }; + internal static unsafe SECURITY_ATTRIBUTES Create(void* lpSecurityDescriptor) => + new SECURITY_ATTRIBUTES + { + nLength = (uint)sizeof(SECURITY_ATTRIBUTES), + lpSecurityDescriptor = lpSecurityDescriptor + }; + internal static unsafe SECURITY_ATTRIBUTES Create(bool inheritable) => new SECURITY_ATTRIBUTES { diff --git a/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs b/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs index 3d09f196608d06..2ca88deabf1414 100644 --- a/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs +++ b/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs @@ -77,8 +77,7 @@ public static unsafe void CreateDirectory(string fullPath, byte[]? securityDescr fixed (byte* pSecurityDescriptor = securityDescriptor) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - secAttrs.lpSecurityDescriptor = pSecurityDescriptor; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor); while (stackDir.Count > 0) { diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs index 41155b164fbebd..e7e777cf71e857 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs @@ -215,15 +215,13 @@ public unsafe RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck } } - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); byte[]? securityDescriptor = registrySecurity?.GetSecurityDescriptorBinaryForm(); fixed (void* pSecurityDescriptor = securityDescriptor) { - if (pSecurityDescriptor is not null) - { - secAttrs.lpSecurityDescriptor = pSecurityDescriptor; - } + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = pSecurityDescriptor is not null + ? Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor) + : Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); // By default, the new key will be writable. int ret = Interop.Advapi32.RegCreateKeyEx(_hkey, diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs index a2d76c604a25d6..8fafab5771293d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs @@ -58,8 +58,7 @@ private unsafe void CreateEventCore( if (options.CurrentUserOnly) { securityDescriptorInfo = new(CurrentUserOnlyAceRights); - securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - securityAttributes.lpSecurityDescriptor = (void*)securityDescriptorInfo.SecurityDescriptor; + securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((void*)securityDescriptorInfo.SecurityDescriptor); securityAttributesPtr = &securityAttributes; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs index 74a9a3ef4bcb57..74064811ed5681 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs @@ -48,8 +48,7 @@ private unsafe void CreateMutexCore( if (options.CurrentUserOnly) { securityDescriptorInfo = new(CurrentUserOnlyAceRights); - securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - securityAttributes.lpSecurityDescriptor = (void*)securityDescriptorInfo.SecurityDescriptor; + securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((void*)securityDescriptorInfo.SecurityDescriptor); securityAttributesPtr = &securityAttributes; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs index ab597e1b08b3d1..fab00cfb2a5819 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs @@ -62,8 +62,7 @@ private unsafe void CreateSemaphoreCore( if (options.CurrentUserOnly) { securityDescriptorInfo = new(CurrentUserOnlyAceRights); - securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - securityAttributes.lpSecurityDescriptor = (void*)securityDescriptorInfo.SecurityDescriptor; + securityAttributes = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((void*)securityDescriptorInfo.SecurityDescriptor); securityAttributesPtr = &securityAttributes; } } diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs index 4e43d709a51c81..bc8035e3d19c1c 100644 --- a/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs +++ b/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs @@ -46,8 +46,7 @@ public static unsafe EventWaitHandle Create(bool initialState, EventResetMode mo fixed (byte* pSecurityDescriptor = eventSecurity.GetSecurityDescriptorBinaryForm()) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - secAttrs.lpSecurityDescriptor = pSecurityDescriptor; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor); SafeWaitHandle handle = Interop.Kernel32.CreateEventEx( (IntPtr)(&secAttrs), diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs index 13aaef9f46eb93..976c6dd98220e3 100644 --- a/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs +++ b/src/libraries/System.Threading.AccessControl/src/System/Threading/MutexAcl.cs @@ -31,8 +31,7 @@ public static unsafe Mutex Create(bool initiallyOwned, string? name, out bool cr fixed (byte* pSecurityDescriptor = mutexSecurity.GetSecurityDescriptorBinaryForm()) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - secAttrs.lpSecurityDescriptor = pSecurityDescriptor; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor); SafeWaitHandle handle = Interop.Kernel32.CreateMutexEx( (IntPtr)(&secAttrs), diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs index db7c400474dc65..07507eb6f7ae12 100644 --- a/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs +++ b/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs @@ -48,8 +48,7 @@ public static unsafe Semaphore Create(int initialCount, int maximumCount, string fixed (byte* pSecurityDescriptor = semaphoreSecurity.GetSecurityDescriptorBinaryForm()) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); - secAttrs.lpSecurityDescriptor = pSecurityDescriptor; + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor); SafeWaitHandle handle = Interop.Kernel32.CreateSemaphoreEx( (IntPtr)(&secAttrs), From c4e787ad06b44dc16ccb15bc9c92f7bf5b778a83 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 07:08:36 +0000 Subject: [PATCH 5/8] Delete GetSecAttrs helper from MemoryMappedFile.Windows.cs, inline Create calls directly Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../MemoryMappedFiles/MemoryMappedFile.Windows.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs index c35d4ea8394d72..1210d8945ba8a4 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs @@ -36,9 +36,7 @@ private static SafeMemoryMappedFileHandle CreateCore( { Debug.Assert(fileHandle is null || fileSize >= 0); - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability); - - if (fileHandle != null) + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((inheritability & HandleInheritability.Inheritable) != 0); { VerifyMemoryMappedFileAccess(access, capacity, fileSize); } @@ -107,7 +105,7 @@ private static SafeMemoryMappedFileHandle CreateOrOpenCore( Debug.Assert(access != MemoryMappedFileAccess.Write, "Callers requesting write access shouldn't try to create a mmf"); SafeMemoryMappedFileHandle? handle = null; - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability); + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((inheritability & HandleInheritability.Inheritable) != 0); int waitRetries = 14; //((2^13)-1)*10ms == approximately 1.4mins int waitSleep = 0; @@ -249,12 +247,5 @@ private static SafeMemoryMappedFileHandle OpenCore( } return handle; } - - /// - /// Helper method used to extract the native binary security descriptor from the MemoryMappedFileSecurity - /// type. If pinningHandle is not null, caller must free it AFTER the call to CreateFile has returned. - /// - private static Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability) => - Interop.Kernel32.SECURITY_ATTRIBUTES.Create((inheritability & HandleInheritability.Inheritable) != 0); } } From b74209c136c35fdddc97949a474047151c7fd1ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 07:16:21 +0000 Subject: [PATCH 6/8] Rename lpSecurityDescriptor param to securityDescriptor; remove unnecessary null check in RegistryKey Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs | 4 ++-- .../src/Microsoft/Win32/RegistryKey.cs | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs index 248657a6ac1dcc..d0740344597f79 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SECURITY_ATTRIBUTES.cs @@ -20,11 +20,11 @@ internal static unsafe SECURITY_ATTRIBUTES Create() => nLength = (uint)sizeof(SECURITY_ATTRIBUTES) }; - internal static unsafe SECURITY_ATTRIBUTES Create(void* lpSecurityDescriptor) => + internal static unsafe SECURITY_ATTRIBUTES Create(void* securityDescriptor) => new SECURITY_ATTRIBUTES { nLength = (uint)sizeof(SECURITY_ATTRIBUTES), - lpSecurityDescriptor = lpSecurityDescriptor + lpSecurityDescriptor = securityDescriptor }; internal static unsafe SECURITY_ATTRIBUTES Create(bool inheritable) => diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs index e7e777cf71e857..0aa1b22d5f316d 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs @@ -219,9 +219,7 @@ public unsafe RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck fixed (void* pSecurityDescriptor = securityDescriptor) { - Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = pSecurityDescriptor is not null - ? Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor) - : Interop.Kernel32.SECURITY_ATTRIBUTES.Create(); + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create(pSecurityDescriptor); // By default, the new key will be writable. int ret = Interop.Advapi32.RegCreateKeyEx(_hkey, From 11f93bcb1fae4385046c90ae32af378c530ab40c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 10:55:55 +0000 Subject: [PATCH 7/8] Fix IDE0059: remove unnecessary = default initialization of securityAttributes Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Threading/EventWaitHandle.Windows.cs | 2 +- .../src/System/Threading/Mutex.Windows.cs | 2 +- .../src/System/Threading/Semaphore.Windows.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs index 8fafab5771293d..8d4e75df747a07 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs @@ -51,7 +51,7 @@ private unsafe void CreateEventCore( SafeWaitHandle handle; int errorCode; Thread.CurrentUserSecurityDescriptorInfo securityDescriptorInfo = default; - Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributes = default; + Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributes; if (!string.IsNullOrEmpty(name) && options.WasSpecified) { name = options.GetNameWithSessionPrefix(name); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs index 74064811ed5681..b3f0f1c9214757 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs @@ -40,7 +40,7 @@ private unsafe void CreateMutexCore( out bool createdNew) { Thread.CurrentUserSecurityDescriptorInfo securityDescriptorInfo = default; - Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributes = default; + Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributes; Interop.Kernel32.SECURITY_ATTRIBUTES* securityAttributesPtr = null; if (!string.IsNullOrEmpty(name) && options.WasSpecified) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs index fab00cfb2a5819..7d65881f367fce 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs @@ -55,7 +55,7 @@ private unsafe void CreateSemaphoreCore( SafeWaitHandle myHandle; int errorCode; Thread.CurrentUserSecurityDescriptorInfo securityDescriptorInfo = default; - Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributes = default; + Interop.Kernel32.SECURITY_ATTRIBUTES securityAttributes; if (!string.IsNullOrEmpty(name) && options.WasSpecified) { name = options.GetNameWithSessionPrefix(name); From 0a9677245cf1e48bf37e74eeabf1aab8b6fe0f6e Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 18 Mar 2026 12:05:19 +0100 Subject: [PATCH 8/8] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs index 1210d8945ba8a4..e63931483b5b88 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs @@ -37,6 +37,8 @@ private static SafeMemoryMappedFileHandle CreateCore( Debug.Assert(fileHandle is null || fileSize >= 0); Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = Interop.Kernel32.SECURITY_ATTRIBUTES.Create((inheritability & HandleInheritability.Inheritable) != 0); + + if (fileHandle is not null) { VerifyMemoryMappedFileAccess(access, capacity, fileSize); }