From: Jan Kotas Date: Wed, 4 Jan 2017 14:31:17 +0000 (-0800) Subject: Path normalization performance improvements X-Git-Tag: submit/tizen/20210909.063632~11030^2~8523^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f45570af2a4585a801a0d1883d20a0359956db5d;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Path normalization performance improvements - Use const variant of path separators in the Path implementation - Add fast paths for common cases to hot parsing routines - Avoid redundant caches for MaxPath on Unix Commit migrated from https://github.com/dotnet/coreclr/commit/d682dd337ccdc71e29a762d9bda8bf2cca93c122 --- diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/Path.Unix.cs b/src/coreclr/src/mscorlib/corefx/System/IO/Path.Unix.cs index 2dd1907..c566fa0 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/Path.Unix.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/Path.Unix.cs @@ -10,16 +10,11 @@ namespace System.IO { public static partial class Path { - public static readonly char DirectorySeparatorChar = '/'; - public static readonly char VolumeSeparatorChar = '/'; - public static readonly char PathSeparator = ':'; - - private const string DirectorySeparatorCharAsString = "/"; - public static char[] GetInvalidFileNameChars() => new char[] { '\0', '/' }; - internal static readonly int MaxPath = Interop.Sys.MaxPath; - private static readonly int MaxLongPath = MaxPath; + public static char[] GetInvalidPathChars() => new char[] { '\0' }; + + internal static int MaxPath => Interop.Sys.MaxPath; private static readonly bool s_isMac = Interop.Sys.GetUnixName() == "OSX"; @@ -47,12 +42,12 @@ namespace System.IO Debug.Assert(collapsedString.Length < path.Length || collapsedString.ToString() == path, "Either we've removed characters, or the string should be unmodified from the input path."); - if (collapsedString.Length > MaxPath) + if (collapsedString.Length > Interop.Sys.MaxPath) { throw new PathTooLongException(SR.IO_PathTooLong); } - string result = collapsedString.Length == 0 ? DirectorySeparatorCharAsString : collapsedString; + string result = collapsedString.Length == 0 ? PathInternal.DirectorySeparatorCharAsString : collapsedString; return result; } @@ -125,15 +120,15 @@ namespace System.IO } } - if (++componentCharCount > PathInternal.MaxComponentLength) + if (++componentCharCount > Interop.Sys.MaxName) { throw new PathTooLongException(SR.IO_PathTooLong); } // Normalize the directory separator if needed - if (c != Path.DirectorySeparatorChar && c == Path.AltDirectorySeparatorChar) + if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) { - c = Path.DirectorySeparatorChar; + c = PathInternal.DirectorySeparatorChar; flippedSeparator = true; } @@ -169,7 +164,7 @@ namespace System.IO return string.IsNullOrEmpty(path) ? DefaultTempPath : PathInternal.IsDirectorySeparator(path[path.Length - 1]) ? path : - path + DirectorySeparatorChar; + path + PathInternal.DirectorySeparatorChar; } public static string GetTempFileName() @@ -197,58 +192,23 @@ namespace System.IO return false; PathInternal.CheckInvalidPathChars(path); - return path.Length > 0 && path[0] == DirectorySeparatorChar; + return path.Length > 0 && path[0] == PathInternal.DirectorySeparatorChar; } public static string GetPathRoot(string path) { if (path == null) return null; - return IsPathRooted(path) ? DirectorySeparatorCharAsString : String.Empty; + return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : String.Empty; } private static unsafe void GetCryptoRandomBytes(byte* bytes, int byteCount) { -#if FEATURE_CORECLR // We want to avoid dependencies on the Crypto library when compiling in CoreCLR. This // will use the existing PAL implementation. byte[] buffer = new byte[KeyLength]; Microsoft.Win32.Win32Native.Random(bStrong: true, buffer: buffer, length: KeyLength); Runtime.InteropServices.Marshal.Copy(buffer, 0, (IntPtr)bytes, KeyLength); -#else - if (s_isMac) - { - GetCryptoRandomBytesApple(bytes, byteCount); - } - else - { - GetCryptoRandomBytesOpenSsl(bytes, byteCount); - } -#endif - } - -#if !FEATURE_CORECLR - private static unsafe void GetCryptoRandomBytesApple(byte* bytes, int byteCount) - { - Debug.Assert(bytes != null); - Debug.Assert(byteCount >= 0); - - if (Interop.CommonCrypto.CCRandomGenerateBytes(bytes, byteCount) != 0) - { - throw new InvalidOperationException(SR.InvalidOperation_Cryptography); - } - } - - private static unsafe void GetCryptoRandomBytesOpenSsl(byte* bytes, int byteCount) - { - Debug.Assert(bytes != null); - Debug.Assert(byteCount >= 0); - - if (!Interop.Crypto.GetRandomBytes(bytes, byteCount)) - { - throw new InvalidOperationException(SR.InvalidOperation_Cryptography); - } } -#endif /// Gets whether the system is case-sensitive. internal static bool IsCaseSensitive { get { return !s_isMac; } } diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/Path.Windows.cs b/src/coreclr/src/mscorlib/corefx/System/IO/Path.Windows.cs index b597efc..0c96769 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/Path.Windows.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/Path.Windows.cs @@ -9,14 +9,8 @@ namespace System.IO { public static partial class Path { - public static readonly char DirectorySeparatorChar = '\\'; - public static readonly char VolumeSeparatorChar = ':'; - public static readonly char PathSeparator = ';'; - - private const string DirectorySeparatorCharAsString = "\\"; - public static char[] GetInvalidFileNameChars() => new char[] - { + { '\"', '<', '>', '|', '\0', (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, @@ -24,10 +18,18 @@ namespace System.IO (char)31, ':', '*', '?', '\\', '/' }; + public static char[] GetInvalidPathChars() => new char[] + { + '|', '\0', + (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, + (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, + (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, + (char)31 + }; + // The max total path is 260, and the max individual component length is 255. // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars. - internal static readonly int MaxPath = 260; - internal static readonly int MaxLongPath = short.MaxValue; + internal const int MaxPath = 260; // Expands the given path to a fully qualified path. public static string GetFullPath(string path) @@ -64,9 +66,9 @@ namespace System.IO // Move past the colon startIndex += 2; - if ((path.Length > 0 && path[0] == VolumeSeparatorChar) - || (path.Length >= startIndex && path[startIndex - 1] == VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) - || (path.Length > startIndex && path.IndexOf(VolumeSeparatorChar, startIndex) != -1)) + if ((path.Length > 0 && path[0] == PathInternal.VolumeSeparatorChar) + || (path.Length >= startIndex && path[startIndex - 1] == PathInternal.VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) + || (path.Length > startIndex && path.IndexOf(PathInternal.VolumeSeparatorChar, startIndex) != -1)) { throw new NotSupportedException(SR.Argument_PathFormatNotSupported); } @@ -121,7 +123,7 @@ namespace System.IO int length = path.Length; if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) || - (length >= 2 && path[1] == VolumeSeparatorChar)) + (length >= 2 && path[1] == PathInternal.VolumeSeparatorChar)) return true; } return false; diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/Path.cs b/src/coreclr/src/mscorlib/corefx/System/IO/Path.cs index 3b1ba6b..77b2139 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/Path.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/Path.cs @@ -13,10 +13,12 @@ namespace System.IO // but they will handle most string operations. public static partial class Path { - // Platform specific alternate directory separator character. - // There is only one directory separator char on Unix, which is the same - // as the alternate separator on Windows, so same definition is used for both. - public static readonly char AltDirectorySeparatorChar = '/'; + // Public static readonly variant of the separators. The Path implementation itself is using + // internal const variant of the separators for better performance. + public static readonly char DirectorySeparatorChar = PathInternal.DirectorySeparatorChar; + public static readonly char AltDirectorySeparatorChar = PathInternal.AltDirectorySeparatorChar; + public static readonly char VolumeSeparatorChar = PathInternal.VolumeSeparatorChar; + public static readonly char PathSeparator = PathInternal.PathSeparator; // For generating random file names // 8 random bytes provides 12 chars in our encoding for the 8.3 name. @@ -90,11 +92,6 @@ namespace System.IO return null; } - public static char[] GetInvalidPathChars() - { - return PathInternal.GetInvalidPathChars(); - } - // Returns the extension of the given path. The returned value includes the // period (".") character of the extension except when you have a terminal period when you get string.Empty, such as ".exe" or // ".cpp". The returned value is null if the given path is @@ -290,7 +287,7 @@ namespace System.IO char ch = finalPath[finalPath.Length - 1]; if (!PathInternal.IsDirectoryOrVolumeSeparator(ch)) { - finalPath.Append(DirectorySeparatorChar); + finalPath.Append(PathInternal.DirectorySeparatorChar); } finalPath.Append(paths[i]); @@ -314,7 +311,7 @@ namespace System.IO char ch = path1[path1.Length - 1]; return PathInternal.IsDirectoryOrVolumeSeparator(ch) ? path1 + path2 : - path1 + DirectorySeparatorCharAsString + path2; + path1 + PathInternal.DirectorySeparatorCharAsString + path2; } private static string CombineNoChecks(string path1, string path2, string path3) @@ -340,11 +337,11 @@ namespace System.IO } else if (hasSep1) { - return path1 + path2 + DirectorySeparatorCharAsString + path3; + return path1 + path2 + PathInternal.DirectorySeparatorCharAsString + path3; } else if (hasSep2) { - return path1 + DirectorySeparatorCharAsString + path2 + path3; + return path1 + PathInternal.DirectorySeparatorCharAsString + path2 + path3; } else { @@ -352,9 +349,9 @@ namespace System.IO // a params string[]. Instead, try to use a cached StringBuilder. StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + 2); sb.Append(path1) - .Append(DirectorySeparatorChar) + .Append(PathInternal.DirectorySeparatorChar) .Append(path2) - .Append(DirectorySeparatorChar) + .Append(PathInternal.DirectorySeparatorChar) .Append(path3); return StringBuilderCache.GetStringAndRelease(sb); } @@ -396,19 +393,19 @@ namespace System.IO sb.Append(path1); if (!hasSep1) { - sb.Append(DirectorySeparatorChar); + sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path2); if (!hasSep2) { - sb.Append(DirectorySeparatorChar); + sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path3); if (!hasSep3) { - sb.Append(DirectorySeparatorChar); + sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path4); diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs b/src/coreclr/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs index b6b7b61..7df435f 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs @@ -11,7 +11,7 @@ namespace System.IO /// /// Wrapper to help with path normalization. /// - unsafe internal class PathHelper + internal class PathHelper { // Can't be over 8.3 and be a short name private const int MaxShortName = 12; @@ -186,7 +186,7 @@ namespace System.IO return !PathInternal.IsDevice(ref buffer) && buffer.Length > 1 && buffer[0] == '\\' && buffer[1] == '\\'; } - private static void GetFullPathName(string path, ref StringBuffer fullPath) + private static unsafe void GetFullPathName(string path, ref StringBuffer fullPath) { // If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as // it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here. diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs b/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs index 6c39f99..adc4da7 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs @@ -10,11 +10,15 @@ namespace System.IO /// Contains internal path helpers that are shared between many projects. internal static partial class PathInternal { + internal const char DirectorySeparatorChar = '/'; + internal const char AltDirectorySeparatorChar = '/'; + internal const char VolumeSeparatorChar = '/'; + internal const char PathSeparator = ':'; + + internal const string DirectorySeparatorCharAsString = "/"; + // There is only one invalid path character in Unix private const char InvalidPathChar = '\0'; - internal static char[] GetInvalidPathChars() => new char[] { InvalidPathChar }; - - internal static readonly int MaxComponentLength = Interop.Sys.MaxName; internal const string ParentDirectoryPrefix = @"../"; @@ -34,8 +38,8 @@ namespace System.IO { // The alternate directory separator char is the same as the directory separator, // so we only need to check one. - Debug.Assert(Path.DirectorySeparatorChar == Path.AltDirectorySeparatorChar); - return c == Path.DirectorySeparatorChar; + Debug.Assert(DirectorySeparatorChar == AltDirectorySeparatorChar); + return c == DirectorySeparatorChar; } /// @@ -101,9 +105,9 @@ namespace System.IO { // The directory separator, volume separator, and the alternate directory // separator should be the same on Unix, so we only need to check one. - Debug.Assert(Path.DirectorySeparatorChar == Path.AltDirectorySeparatorChar); - Debug.Assert(Path.DirectorySeparatorChar == Path.VolumeSeparatorChar); - return ch == Path.DirectorySeparatorChar; + Debug.Assert(DirectorySeparatorChar == AltDirectorySeparatorChar); + Debug.Assert(DirectorySeparatorChar == VolumeSeparatorChar); + return ch == DirectorySeparatorChar; } internal static bool HasInvalidVolumeSeparator(string path) diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs b/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs index 712ba05..84953df 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs @@ -86,7 +86,7 @@ namespace System.IO // The only way to specify a fixed path that doesn't begin with two slashes // is the drive, colon, slash format- i.e. C:\ return !((path.Length >= 3) - && (path[1] == Path.VolumeSeparatorChar) + && (path[1] == VolumeSeparatorChar) && IsDirectorySeparator(path[2])); } } diff --git a/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs b/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs index d3e634e..560b9d1 100644 --- a/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs +++ b/src/coreclr/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs @@ -40,6 +40,13 @@ namespace System.IO // Local and Global MS-DOS Device Names // https://msdn.microsoft.com/en-us/library/windows/hardware/ff554302.aspx + internal const char DirectorySeparatorChar = '\\'; + internal const char AltDirectorySeparatorChar = '/'; + internal const char VolumeSeparatorChar = ':'; + internal const char PathSeparator = ';'; + + internal const string DirectorySeparatorCharAsString = "\\"; + internal const string ExtendedPathPrefix = @"\\?\"; internal const string UncPathPrefix = @"\\"; internal const string UncExtendedPrefixToInsert = @"?\UNC\"; @@ -58,22 +65,6 @@ namespace System.IO internal const int UncExtendedPrefixLength = 8; internal const int MaxComponentLength = 255; - internal static char[] GetInvalidPathChars() => new char[] - { - '|', '\0', - (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, - (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, - (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, - (char)31 - }; - - // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression - // https://msdn.microsoft.com/en-us/library/ff469270.aspx - private static readonly char[] s_wildcardChars = - { - '\"', '<', '>', '*', '?' - }; - /// /// Returns true if the given character is a valid drive letter /// @@ -193,10 +184,12 @@ namespace System.IO for (int i = 0; i < path.Length; i++) { char c = path[i]; - - if (c <= '\u001f' || c == '|') + if (c <= '|') // fast path for common case - '|' is highest illegal character { - return true; + if (c <= '\u001f' || c == '|') + { + return true; + } } } @@ -206,13 +199,24 @@ namespace System.IO /// /// Check for known wildcard characters. '*' and '?' are the most common ones. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal unsafe static bool HasWildCardCharacters(string path) + internal static bool HasWildCardCharacters(string path) { // Question mark is part of dos device syntax so we have to skip if we are int startIndex = IsDevice(path) ? ExtendedPathPrefix.Length : 0; - return path.IndexOfAny(s_wildcardChars, startIndex) >= 0; + // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression + // https://msdn.microsoft.com/en-us/library/ff469270.aspx + for (int i = startIndex; i < path.Length; i++) + { + char c = path[i]; + if (c <= '?') // fast path for common case - '?' is highest wildcard character + { + if (c == '\"' || c == '<' || c == '>' || c == '*' || c == '?') + return true; + } + } + + return false; } /// @@ -263,7 +267,7 @@ namespace System.IO while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) i++; } } - else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == Path.VolumeSeparatorChar) + else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == VolumeSeparatorChar) { // Path is at least longer than where we expect a colon, and has a colon (\\?\A:, A:) // If the colon is followed by a directory separator, move past it @@ -314,7 +318,7 @@ namespace System.IO // The only way to specify a fixed path that doesn't begin with two slashes // is the drive, colon, slash format- i.e. C:\ return !((path.Length >= 3) - && (path[1] == Path.VolumeSeparatorChar) + && (path[1] == VolumeSeparatorChar) && IsDirectorySeparator(path[2]) // To match old behavior we'll check the drive character for validity as the path is technically // not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream. @@ -350,7 +354,7 @@ namespace System.IO [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsDirectorySeparator(char c) { - return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar; + return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar; } /// @@ -401,7 +405,7 @@ namespace System.IO { current = path[i]; if (IsDirectorySeparator(current) - && (current != Path.DirectorySeparatorChar + && (current != DirectorySeparatorChar // Check for sequential separators past the first position (we need to keep initial two for UNC/extended) || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))) { @@ -418,7 +422,7 @@ namespace System.IO if (IsDirectorySeparator(path[start])) { start++; - builder.Append(Path.DirectorySeparatorChar); + builder.Append(DirectorySeparatorChar); } for (int i = start; i < path.Length; i++) @@ -435,7 +439,7 @@ namespace System.IO } // Ensure it is the primary separator - current = Path.DirectorySeparatorChar; + current = DirectorySeparatorChar; } builder.Append(current); @@ -450,7 +454,7 @@ namespace System.IO /// The character to test. internal static bool IsDirectoryOrVolumeSeparator(char ch) { - return IsDirectorySeparator(ch) || Path.VolumeSeparatorChar == ch; + return IsDirectorySeparator(ch) || VolumeSeparatorChar == ch; } /// @@ -467,11 +471,11 @@ namespace System.IO int startIndex = IsExtended(path) ? ExtendedPathPrefix.Length : PathStartSkip(path); // If we start with a colon - if ((path.Length > startIndex && path[startIndex] == Path.VolumeSeparatorChar) + if ((path.Length > startIndex && path[startIndex] == VolumeSeparatorChar) // Or have an invalid drive letter and colon - || (path.Length >= startIndex + 2 && path[startIndex + 1] == Path.VolumeSeparatorChar && !IsValidDriveChar(path[startIndex])) + || (path.Length >= startIndex + 2 && path[startIndex + 1] == VolumeSeparatorChar && !IsValidDriveChar(path[startIndex])) // Or have any colons beyond the drive colon - || (path.Length > startIndex + 2 && path.IndexOf(Path.VolumeSeparatorChar, startIndex + 2) != -1)) + || (path.Length > startIndex + 2 && path.IndexOf(VolumeSeparatorChar, startIndex + 2) != -1)) { return true; } diff --git a/src/coreclr/src/mscorlib/corefx/System/Runtime/InteropServices/StringBuffer.cs b/src/coreclr/src/mscorlib/corefx/System/Runtime/InteropServices/StringBuffer.cs index a7d9ed7..8779a63 100644 --- a/src/coreclr/src/mscorlib/corefx/System/Runtime/InteropServices/StringBuffer.cs +++ b/src/coreclr/src/mscorlib/corefx/System/Runtime/InteropServices/StringBuffer.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Buffers; +using System.Runtime.CompilerServices; namespace System.Runtime.InteropServices { @@ -39,11 +40,13 @@ namespace System.Runtime.InteropServices /// Thrown if attempting to index outside of the buffer length. public char this[int index] { + [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (index >= _length) throw new ArgumentOutOfRangeException(nameof(index)); return _buffer[index]; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { if (index >= _length) throw new ArgumentOutOfRangeException(nameof(index)); @@ -233,7 +236,7 @@ namespace System.Runtime.InteropServices /// of characters. /// /// Thrown if is null. - public unsafe void CopyTo(int bufferIndex, ref StringBuffer destination, int destinationIndex, int count) + public void CopyTo(int bufferIndex, ref StringBuffer destination, int destinationIndex, int count) { if (destinationIndex > destination._length) throw new ArgumentOutOfRangeException(nameof(destinationIndex)); if (bufferIndex >= _length) throw new ArgumentOutOfRangeException(nameof(bufferIndex)); @@ -250,7 +253,7 @@ namespace System.Runtime.InteropServices /// Copy contents from the specified string into the buffer at the given index. Start index must be within the current length of /// the buffer, will grow as necessary. /// - public unsafe void CopyFrom(int bufferIndex, string source, int sourceIndex = 0, int count = -1) + public void CopyFrom(int bufferIndex, string source, int sourceIndex = 0, int count = -1) { if (source == null) throw new ArgumentNullException(nameof(source)); if (bufferIndex > _length) throw new ArgumentOutOfRangeException(nameof(bufferIndex)); diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Mutex.cs b/src/coreclr/src/mscorlib/src/System/Threading/Mutex.cs index 506abb7..5ffeecd 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Mutex.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Mutex.cs @@ -153,7 +153,7 @@ namespace System.Threading #if PLATFORM_UNIX case Win32Native.ERROR_FILENAME_EXCED_RANGE: // On Unix, length validation is done by CoreCLR's PAL after converting to utf-8 - throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", PathInternal.MaxComponentLength), "name"); + throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Interop.Sys.MaxName), "name"); #endif case Win32Native.ERROR_INVALID_HANDLE: @@ -294,7 +294,7 @@ namespace System.Threading if (name != null && errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE) { // On Unix, length validation is done by CoreCLR's PAL after converting to utf-8 - throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", PathInternal.MaxComponentLength), nameof(name)); + throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Interop.Sys.MaxName), nameof(name)); } #endif