Remove some calls to wstrcpy (#32342)
authorLevi Broderick <GrabYourPitchforks@users.noreply.github.com>
Fri, 21 Feb 2020 04:54:32 +0000 (20:54 -0800)
committerGitHub <noreply@github.com>
Fri, 21 Feb 2020 04:54:32 +0000 (20:54 -0800)
src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
src/libraries/System.Private.CoreLib/src/System/String.cs

index 486145d..a15d9b9 100644 (file)
@@ -15,7 +15,7 @@ namespace System
     {
         private const int StackallocIntBufferSizeLimit = 128;
 
-        private static unsafe void FillStringChecked(string dest, int destPos, string src)
+        private static void FillStringChecked(string dest, int destPos, string src)
         {
             Debug.Assert(dest != null);
             Debug.Assert(src != null);
@@ -24,11 +24,10 @@ namespace System
                 throw new IndexOutOfRangeException();
             }
 
-            fixed (char* pDest = &dest._firstChar)
-            fixed (char* pSrc = &src._firstChar)
-            {
-                wstrcpy(pDest + destPos, pSrc, src.Length);
-            }
+            Buffer.Memmove(
+                destination: ref Unsafe.Add(ref dest._firstChar, destPos),
+                source: ref src._firstChar,
+                elementCount: (uint)src.Length);
         }
 
         public static string Concat(object? arg0) => arg0?.ToString() ?? string.Empty;
@@ -1665,18 +1664,17 @@ namespace System
             return InternalSubString(startIndex, length);
         }
 
-        private unsafe string InternalSubString(int startIndex, int length)
+        private string InternalSubString(int startIndex, int length)
         {
             Debug.Assert(startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
             Debug.Assert(length >= 0 && startIndex <= this.Length - length, "length is out of range!");
 
             string result = FastAllocateString(length);
 
-            fixed (char* dest = &result._firstChar)
-            fixed (char* src = &_firstChar)
-            {
-                wstrcpy(dest, src + startIndex, length);
-            }
+            Buffer.Memmove(
+                elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
+                destination: ref result._firstChar,
+                source: ref Unsafe.Add(ref _firstChar, startIndex));
 
             return result;
         }
index 177ded2..ec6fc18 100644 (file)
@@ -58,11 +58,12 @@ namespace System
                 return Empty;
 
             string result = FastAllocateString(value.Length);
-            unsafe
-            {
-                fixed (char* dest = &result._firstChar, source = value)
-                    wstrcpy(dest, source, value.Length);
-            }
+
+            Buffer.Memmove(
+                elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
+                destination: ref result._firstChar,
+                source: ref MemoryMarshal.GetArrayDataReference(value));
+
             return result;
         }
 
@@ -91,11 +92,12 @@ namespace System
                 return Empty;
 
             string result = FastAllocateString(length);
-            unsafe
-            {
-                fixed (char* dest = &result._firstChar, source = value)
-                    wstrcpy(dest, source + startIndex, length);
-            }
+
+            Buffer.Memmove(
+                elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
+                destination: ref result._firstChar,
+                source: ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(value), startIndex));
+
             return result;
         }
 
@@ -117,8 +119,12 @@ namespace System
                 return Empty;
 
             string result = FastAllocateString(count);
-            fixed (char* dest = &result._firstChar)
-                wstrcpy(dest, ptr, count);
+
+            Buffer.Memmove(
+                elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
+                destination: ref result._firstChar,
+                source: ref *ptr);
+
             return result;
         }
 
@@ -151,8 +157,12 @@ namespace System
                 throw new ArgumentOutOfRangeException(nameof(ptr), SR.ArgumentOutOfRange_PartialWCHAR);
 
             string result = FastAllocateString(length);
-            fixed (char* dest = &result._firstChar)
-                wstrcpy(dest, pStart, length);
+
+            Buffer.Memmove(
+               elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
+               destination: ref result._firstChar,
+               source: ref *pStart);
+
             return result;
         }
 
@@ -370,8 +380,12 @@ namespace System
                 throw new ArgumentNullException(nameof(str));
 
             string result = FastAllocateString(str.Length);
-            fixed (char* dest = &result._firstChar, src = &str._firstChar)
-                wstrcpy(dest, src, str.Length);
+
+            Buffer.Memmove(
+                elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
+                destination: ref result._firstChar,
+                source: ref str._firstChar);
+
             return result;
         }
 
@@ -393,25 +407,31 @@ namespace System
             if (destinationIndex > destination.Length - count || destinationIndex < 0)
                 throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.ArgumentOutOfRange_IndexCount);
 
-            fixed (char* src = &_firstChar, dest = destination)
-                wstrcpy(dest + destinationIndex, src + sourceIndex, count);
+            Buffer.Memmove(
+                destination: ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(destination), destinationIndex),
+                source: ref Unsafe.Add(ref _firstChar, sourceIndex),
+                elementCount: (uint)count);
         }
 
         // Returns the entire string as an array of characters.
-        public unsafe char[] ToCharArray()
+        public char[] ToCharArray()
         {
             if (Length == 0)
                 return Array.Empty<char>();
 
             char[] chars = new char[Length];
-            fixed (char* src = &_firstChar, dest = &chars[0])
-                wstrcpy(dest, src, Length);
+
+            Buffer.Memmove(
+                destination: ref MemoryMarshal.GetArrayDataReference(chars),
+                source: ref _firstChar,
+                elementCount: (uint)Length);
+
             return chars;
         }
 
         // Returns a substring of this string as an array of characters.
         //
-        public unsafe char[] ToCharArray(int startIndex, int length)
+        public char[] ToCharArray(int startIndex, int length)
         {
             // Range check everything.
             if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
@@ -425,8 +445,12 @@ namespace System
             }
 
             char[] chars = new char[length];
-            fixed (char* src = &_firstChar, dest = &chars[0])
-                wstrcpy(dest, src + startIndex, length);
+
+            Buffer.Memmove(
+               destination: ref MemoryMarshal.GetArrayDataReference(chars),
+               source: ref Unsafe.Add(ref _firstChar, startIndex),
+               elementCount: (uint)length);
+
             return chars;
         }