diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs index 3d2ac0ff2a7c..ebcff1fe0f4e 100644 --- a/src/mscorlib/src/System/String.cs +++ b/src/mscorlib/src/System/String.cs @@ -3174,7 +3174,17 @@ public static String Concat(params Object[] args) { throw new OutOfMemoryException(); } } - return ConcatArray(sArgs, totalLength); + + string result = FastAllocateString(totalLength); + int currPos = 0; + for (int i = 0; i < sArgs.Length; i++) + { + Contract.Assert(currPos <= totalLength - sArgs[i].Length, "[String.Concat](currPos <= totalLength - sArgs[i].Length)"); + FillStringChecked(result, currPos, sArgs[i]); + currPos += sArgs[i].Length; + } + + return result; } [ComVisible(false)] @@ -3319,44 +3329,66 @@ public static String Concat(String str0, String str1, String str2, String str3) return result; } - [System.Security.SecuritySafeCritical] // auto-generated - private static String ConcatArray(String[] values, int totalLength) { - String result = FastAllocateString(totalLength); - int currPos=0; - - for (int i=0; i() != null); - // Spec#: Consider a postcondition saying the length of this string == the sum of each string in array Contract.EndContractBlock(); - int totalLength=0; - // Always make a copy to prevent changing the array on another thread. - String[] internalValues = new String[values.Length]; - - for (int i=0; i int.MaxValue) + { + throw new OutOfMemoryException(); + } + int totalLength = (int)totalLengthLong; + if (totalLength == 0) + { + return string.Empty; + } + + // Allocate a new string and copy each input string into it + string result = FastAllocateString(totalLength); + int copiedLength = 0; + for (int i = 0; i < values.Length; i++) + { + string value = values[i]; + if (!string.IsNullOrEmpty(value)) + { + int valueLen = value.Length; + if (valueLen > totalLength - copiedLength) + { + copiedLength = -1; + break; + } + + FillStringChecked(result, copiedLength, value); + copiedLength += valueLen; + } + } + + // If we copied exactly the right amount, return the new string. Otherwise, + // something changed concurrently to mutate the input array: fall back to + // doing the concatenation again, but this time with a defensive copy. This + // fall back should be extremely rare. + return copiedLength == totalLength ? result : Concat((string[])values.Clone()); } [System.Security.SecuritySafeCritical] // auto-generated