From: Stephen Toub Date: Tue, 17 Nov 2020 22:48:19 +0000 (-0500) Subject: Remove some overhead from Process.Start (#44691) X-Git-Tag: submit/tizen/20210909.063632~4571 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ef2a1878793e7e3fc3060396d3d2655ac53b1316;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Remove some overhead from Process.Start (#44691) - Avoid StringBuilder marshaling - Let CreateProcess{WithLogonW} determine the current working directory - Avoid creating SafeHandles for GetCurrentProcess() - Avoid forcing ProcessStartInfo.ArgumentList into existence just to check if it contains anything - Prefer using ProcessStartInfo.Arguments in Start(string, IEnumerable) if there's only one string in the enumerable - Use ValueStringBuilder instead of StringBuilder to build up arguments, so as to use stack space / pooled char[]s and avoid actually needing to produce strings. - Avoid unnecessary SafeHandle for PROCESS_INFORMATION.hThread --- diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CreateProcessWithLogon.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CreateProcessWithLogon.cs index 61e28bd..da3f4c6 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CreateProcessWithLogon.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CreateProcessWithLogon.cs @@ -12,18 +12,16 @@ internal partial class Interop internal partial class Advapi32 { [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true, BestFitMapping = false, EntryPoint = "CreateProcessWithLogonW")] - internal static extern bool CreateProcessWithLogonW( + internal static extern unsafe bool CreateProcessWithLogonW( string userName, string domain, IntPtr password, LogonFlags logonFlags, string? appName, -#pragma warning disable CA1838 // reasonable use of StringBuilder to build up a command line - [In] StringBuilder cmdLine, -#pragma warning restore CA1838 + char* cmdLine, int creationFlags, IntPtr environmentBlock, - string lpCurrentDirectory, + string? lpCurrentDirectory, ref Interop.Kernel32.STARTUPINFO lpStartupInfo, ref Interop.Kernel32.PROCESS_INFORMATION lpProcessInformation); diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.OpenProcessToken.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.OpenProcessToken.cs index 2fd2afb..7e8e225 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.OpenProcessToken.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.OpenProcessToken.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Win32.SafeHandles; +using System; using System.Runtime.InteropServices; internal partial class Interop @@ -9,6 +10,6 @@ internal partial class Interop internal partial class Advapi32 { [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool OpenProcessToken(SafeProcessHandle ProcessHandle, int DesiredAccess, out SafeTokenHandle TokenHandle); + internal static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, out SafeTokenHandle TokenHandle); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.CreateProcess.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.CreateProcess.cs index 95a17f1..2961693 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.CreateProcess.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.CreateProcess.cs @@ -13,17 +13,15 @@ internal partial class Interop internal partial class Kernel32 { [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, EntryPoint = "CreateProcessW")] - internal static extern bool CreateProcess( + internal static extern unsafe bool CreateProcess( string? lpApplicationName, -#pragma warning disable CA1838 // reasonable use of StringBuilder to build up a command line - [In] StringBuilder lpCommandLine, -#pragma warning restore CA1838 + char* lpCommandLine, ref SECURITY_ATTRIBUTES procSecAttrs, ref SECURITY_ATTRIBUTES threadSecAttrs, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, - string lpCurrentDirectory, + string? lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, ref PROCESS_INFORMATION lpProcessInformation ); diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeAccessTokenHandle.cs similarity index 90% rename from src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle.cs rename to src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeAccessTokenHandle.cs index 9233ed6..fff392d 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeAccessTokenHandle.cs @@ -9,7 +9,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] + [DllImport(Libraries.Kernel32, SetLastError = true)] internal static extern bool DuplicateHandle( IntPtr hSourceProcessHandle, IntPtr hSourceHandle, diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeFileHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeFileHandle.cs new file mode 100644 index 0000000..fb54231 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeFileHandle.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32, SetLastError = true)] + internal static extern bool DuplicateHandle( + IntPtr hSourceProcessHandle, + SafeHandle hSourceHandle, + IntPtr hTargetProcess, + out SafeFileHandle targetHandle, + int dwDesiredAccess, + bool bInheritHandle, + int dwOptions + ); + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_IntPtr.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafePipeHandle.cs similarity index 71% rename from src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_IntPtr.cs rename to src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafePipeHandle.cs index 19a596f..96726ab 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_IntPtr.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafePipeHandle.cs @@ -5,20 +5,18 @@ using Microsoft.Win32.SafeHandles; using System; using System.Runtime.InteropServices; -internal partial class Interop +internal static partial class Interop { - internal partial class Kernel32 + internal static partial class Kernel32 { [DllImport(Libraries.Kernel32, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool DuplicateHandle( IntPtr hSourceProcessHandle, - SafePipeHandle hSourceHandle, + SafeHandle hSourceHandle, IntPtr hTargetProcessHandle, out SafePipeHandle lpTargetHandle, uint dwDesiredAccess, - [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, + bool bInheritHandle, uint dwOptions); - } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeProcessHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeProcessHandle.cs deleted file mode 100644 index 7bf1c06..0000000 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeProcessHandle.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Win32.SafeHandles; -using System; -using System.Runtime.InteropServices; - -internal partial class Interop -{ - internal partial class Kernel32 - { - [DllImport(Libraries.Kernel32, SetLastError = true, BestFitMapping = false)] - internal static extern bool DuplicateHandle( - SafeProcessHandle hSourceProcessHandle, - SafeHandle hSourceHandle, - SafeProcessHandle hTargetProcess, - out SafeFileHandle targetHandle, - int dwDesiredAccess, - bool bInheritHandle, - int dwOptions - ); - - [DllImport(Libraries.Kernel32, SetLastError = true, BestFitMapping = false)] - internal static extern bool DuplicateHandle( - SafeProcessHandle hSourceProcessHandle, - SafeHandle hSourceHandle, - SafeProcessHandle hTargetProcess, - out SafeWaitHandle targetHandle, - int dwDesiredAccess, - bool bInheritHandle, - int dwOptions - ); - - } -} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeWaitHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeWaitHandle.cs new file mode 100644 index 0000000..5749d82 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DuplicateHandle_SafeWaitHandle.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32, SetLastError = true)] + internal static extern bool DuplicateHandle( + IntPtr hSourceProcessHandle, + SafeHandle hSourceHandle, + IntPtr hTargetProcess, + out SafeWaitHandle targetHandle, + int dwDesiredAccess, + bool bInheritHandle, + int dwOptions + ); + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess_IntPtr.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess.cs similarity index 100% rename from src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess_IntPtr.cs rename to src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess.cs diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess_SafeProcessHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess_SafeProcessHandle.cs deleted file mode 100644 index 36cb3da..0000000 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentProcess_SafeProcessHandle.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Win32.SafeHandles; -using System.Runtime.InteropServices; - -internal partial class Interop -{ - internal partial class Kernel32 - { - [DllImport(Libraries.Kernel32, SetLastError = true)] - internal static extern SafeProcessHandle GetCurrentProcess(); - } -} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ProcessWaitHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ProcessWaitHandle.cs index d6f0827..134e366 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ProcessWaitHandle.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ProcessWaitHandle.cs @@ -3,6 +3,7 @@ #nullable enable using Microsoft.Win32.SafeHandles; +using System; using System.Runtime.InteropServices; using System.Threading; @@ -14,20 +15,21 @@ internal partial class Interop { internal ProcessWaitHandle(SafeProcessHandle processHandle) { - SafeWaitHandle? waitHandle; - SafeProcessHandle currentProcHandle = Interop.Kernel32.GetCurrentProcess(); - bool succeeded = Interop.Kernel32.DuplicateHandle( + IntPtr currentProcHandle = GetCurrentProcess(); + bool succeeded = DuplicateHandle( currentProcHandle, processHandle, currentProcHandle, - out waitHandle, + out SafeWaitHandle waitHandle, 0, false, - Interop.Kernel32.HandleOptions.DUPLICATE_SAME_ACCESS); + HandleOptions.DUPLICATE_SAME_ACCESS); if (!succeeded) { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); + int error = Marshal.GetHRForLastWin32Error(); + waitHandle.Dispose(); + Marshal.ThrowExceptionForHR(error); } this.SetSafeWaitHandle(waitHandle); diff --git a/src/libraries/Common/tests/TestUtilities/System/AdminHelpers.cs b/src/libraries/Common/tests/TestUtilities/System/AdminHelpers.cs index e60459e..67c9a00 100644 --- a/src/libraries/Common/tests/TestUtilities/System/AdminHelpers.cs +++ b/src/libraries/Common/tests/TestUtilities/System/AdminHelpers.cs @@ -40,9 +40,8 @@ namespace System return(userId == 0); } - IntPtr processHandle = Interop.Kernel32.GetCurrentProcess(); SafeAccessTokenHandle token; - if (!Interop.Advapi32.OpenProcessToken(processHandle, TokenAccessLevels.Read, out token)) + if (!Interop.Advapi32.OpenProcessToken(Interop.Kernel32.GetCurrentProcess(), TokenAccessLevels.Read, out token)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Open process token failed"); } diff --git a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj index 5943195..6e5f45f 100644 --- a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj +++ b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj @@ -35,8 +35,8 @@ - + - + - @@ -151,4 +151,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj index 7799b1f..c7f5c57 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -1,4 +1,4 @@ - + $(DefineConstants);FEATURE_REGISTRY true @@ -40,7 +40,9 @@ + Link="Common\System\Threading\Tasks\TaskTimeoutExtensions.cs" /> + - @@ -143,8 +145,10 @@ Link="Common\Interop\Windows\Kernel32\Interop.GetPriorityClass.cs" /> - + + - fileName = startInfo.FileName.AsSpan().Trim(); bool fileNameIsQuoted = fileName.Length > 0 && fileName[0] == '\"' && fileName[fileName.Length - 1] == '\"'; if (!fileNameIsQuoted) @@ -683,9 +687,7 @@ namespace System.Diagnostics commandLine.Append('"'); } - startInfo.AppendArgumentsTo(commandLine); - - return commandLine; + startInfo.AppendArgumentsTo(ref commandLine); } /// Gets timing information for the current process. @@ -713,15 +715,13 @@ namespace System.Diagnostics private static unsafe void SetPrivilege(string privilegeName, int attrib) { // this is only a "pseudo handle" to the current process - no need to close it later - SafeProcessHandle processHandle = Interop.Kernel32.GetCurrentProcess(); - SafeTokenHandle? hToken = null; try { // get the process token so we can adjust the privilege on it. We DO need to // close the token when we're done with it. - if (!Interop.Advapi32.OpenProcessToken(processHandle, Interop.Kernel32.HandleOptions.TOKEN_ADJUST_PRIVILEGES, out hToken)) + if (!Interop.Advapi32.OpenProcessToken(Interop.Kernel32.GetCurrentProcess(), Interop.Kernel32.HandleOptions.TOKEN_ADJUST_PRIVILEGES, out hToken)) { throw new Win32Exception(); } @@ -760,7 +760,7 @@ namespace System.Diagnostics /// Note that the handle we stored in current process object will have all access we need. /// /// - private SafeProcessHandle GetProcessHandle(int access, bool throwIfExited) + private SafeProcessHandle GetProcessHandle(int access, bool throwIfExited = true) { if (_haveProcessHandle) { @@ -773,10 +773,9 @@ namespace System.Diagnostics { if (waitHandle.WaitOne(0)) { - if (_haveProcessId) - throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, _processId.ToString())); - else - throw new InvalidOperationException(SR.ProcessHasExitedNoId); + throw new InvalidOperationException(_haveProcessId ? + SR.Format(SR.ProcessHasExited, _processId.ToString()) : + SR.ProcessHasExitedNoId); } } } @@ -789,8 +788,7 @@ namespace System.Diagnostics else { EnsureState(State.HaveId | State.IsLocal); - SafeProcessHandle handle = SafeProcessHandle.InvalidHandle; - handle = ProcessManager.OpenProcess(_processId, access, throwIfExited); + SafeProcessHandle handle = ProcessManager.OpenProcess(_processId, access, throwIfExited); if (throwIfExited && (access & Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION) != 0) { if (Interop.Kernel32.GetExitCodeProcess(handle, out _exitCode) && _exitCode != Interop.Kernel32.HandleOptions.STILL_ACTIVE) @@ -802,16 +800,6 @@ namespace System.Diagnostics } } - /// - /// Gets a short-term handle to the process, with the given access. If a handle exists, - /// then it is reused. If the process has exited, it throws an exception. - /// - /// - private SafeProcessHandle GetProcessHandle(int access) - { - return GetProcessHandle(access, true); - } - private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, ref Interop.Kernel32.SECURITY_ATTRIBUTES lpPipeAttributes, int nSize) { bool ret = Interop.Kernel32.CreatePipe(out hReadPipe, out hWritePipe, ref lpPipeAttributes, nSize); @@ -852,7 +840,7 @@ namespace System.Diagnostics // One potential theory is that child process can do something brain dead like // closing the parent end of the pipe and there by getting into a blocking situation // as parent will not be draining the pipe at the other end anymore. - SafeProcessHandle currentProcHandle = Interop.Kernel32.GetCurrentProcess(); + IntPtr currentProcHandle = Interop.Kernel32.GetCurrentProcess(); if (!Interop.Kernel32.DuplicateHandle(currentProcHandle, hTmp, currentProcHandle, diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index ab5e7be..53fd787 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1218,7 +1218,7 @@ namespace System.Diagnostics { throw new InvalidOperationException(SR.StandardErrorEncodingNotAllowed); } - if (!string.IsNullOrEmpty(startInfo.Arguments) && startInfo.ArgumentList.Count > 0) + if (!string.IsNullOrEmpty(startInfo.Arguments) && startInfo.HasArgumentList) { throw new InvalidOperationException(SR.ArgumentAndArgumentListInitialized); } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs index 050afb5..6379245 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs @@ -63,17 +63,9 @@ namespace System.Diagnostics set => _arguments = value; } - public Collection ArgumentList - { - get - { - if (_argumentList == null) - { - _argumentList = new Collection(); - } - return _argumentList; - } - } + public Collection ArgumentList => _argumentList ??= new Collection(); + + internal bool HasArgumentList => _argumentList is not null && _argumentList.Count != 0; public bool CreateNoWindow { get; set; } @@ -176,25 +168,23 @@ namespace System.Diagnostics internal string BuildArguments() { - if (_argumentList == null || _argumentList.Count == 0) + if (HasArgumentList) { - return Arguments; - } - else - { - var stringBuilder = new StringBuilder(); - AppendArgumentsTo(stringBuilder); - return stringBuilder.ToString(); + var arguments = new ValueStringBuilder(stackalloc char[256]); + AppendArgumentsTo(ref arguments); + return arguments.ToString(); } + + return Arguments; } - internal void AppendArgumentsTo(StringBuilder stringBuilder) + internal void AppendArgumentsTo(ref ValueStringBuilder stringBuilder) { if (_argumentList != null && _argumentList.Count > 0) { foreach (string argument in _argumentList) { - PasteArguments.AppendArgument(stringBuilder, argument); + PasteArguments.AppendArgument(ref stringBuilder, argument); } } else if (!string.IsNullOrEmpty(Arguments)) diff --git a/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj b/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj index 74794bd..e13a604 100644 --- a/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj +++ b/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj @@ -15,6 +15,8 @@ Link="Common\System\ShouldNotBeInvokedException.cs" /> + diff --git a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj index b322b78..66f0da7 100644 --- a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj +++ b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj @@ -48,13 +48,13 @@ - + - + + Link="Common\Interop\Windows\Interop.GetFileType.cs" /> Common\Interop\Windows\Kernel32\Interop.GetCurrentDirectory.cs - - Common\Interop\Windows\Kernel32\Interop.GetCurrentProcess_IntPtr.cs + + Common\Interop\Windows\Kernel32\Interop.GetCurrentProcess.cs Common\Interop\Windows\Kernel32\Interop.GetCurrentProcessId.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Unix.cs index d85004c..f4d8b7a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Unix.cs @@ -14,10 +14,10 @@ namespace System /// internal static string Paste(IEnumerable arguments, bool pasteFirstArgumentUsingArgV0Rules) { - var stringBuilder = new StringBuilder(); + var stringBuilder = new ValueStringBuilder(stackalloc char[256]); foreach (string argument in arguments) { - AppendArgument(stringBuilder, argument); + AppendArgument(ref stringBuilder, argument); } return stringBuilder.ToString(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Windows.cs index fb1394f..06f7e9d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/PasteArguments.Windows.cs @@ -14,7 +14,7 @@ namespace System /// internal static string Paste(IEnumerable arguments, bool pasteFirstArgumentUsingArgV0Rules) { - var stringBuilder = new StringBuilder(); + var stringBuilder = new ValueStringBuilder(stackalloc char[256]); foreach (string argument in arguments) { @@ -53,7 +53,7 @@ namespace System } else { - AppendArgument(stringBuilder, argument); + AppendArgument(ref stringBuilder, argument); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs b/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs index 189d2f1..39008fc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs +++ b/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs @@ -7,7 +7,7 @@ namespace System { internal static partial class PasteArguments { - internal static void AppendArgument(StringBuilder stringBuilder, string argument) + internal static void AppendArgument(ref ValueStringBuilder stringBuilder, string argument) { if (stringBuilder.Length != 0) { diff --git a/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj b/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj index c4579f6..1273cc6 100644 --- a/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj +++ b/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj @@ -67,8 +67,8 @@ Link="Common\Interop\Interop.OpenThreadToken_SafeTokenHandle.cs" /> - + - @@ -59,8 +59,8 @@ Link="Common\Interop\Interop.GetTokenInformation.cs" /> - + - \ No newline at end of file +