diff options
author | Maryam Ariyan <maryam.ariyan@microsoft.com> | 2018-03-23 19:29:55 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2018-03-23 22:08:28 +0300 |
commit | 9df718944af1a0ff17deac41810fc0a2a391d264 (patch) | |
tree | 9ffb75b6e534ece45f43e0b635e1abb9372b04f7 /src | |
parent | 85b8a261218078071e6ab147e37521b92948ea79 (diff) |
Fixes StringBuilder unbounded size growth in Clear() when we use a mix of Append and Insert (#16926)
* Fixing Clear infinitely growing when we combine usage of Insert and Append. Fixes #27625
* Move debug code to StringBuilder.Debug.cs and Applied code review feedback
* Adding missing debug condition check
* Adding comments and moving Condition on projitems after filename
* Moving the infinite capacity growth fix to Length setter
* Removing originalCapacity and Debug.Assert
* Applying PR feedbacks
* Minor cleanup
* simplifying to single loop
* keeping just one method for ShowChunks function
Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Diffstat (limited to 'src')
3 files changed, 44 insertions, 5 deletions
diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 270d06d3c..f4f8dd32a 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -521,6 +521,7 @@ <Compile Include="$(MSBuildThisFileDirectory)System\Text\Latin1Encoding.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Text\NormalizationForm.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.Debug.cs" Condition="'$(Configuration)' == 'Debug'" /> <Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeEncoding.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF32Encoding.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF7Encoding.cs" /> diff --git a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.Debug.cs b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.Debug.cs new file mode 100644 index 000000000..c2c8c9f7f --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.Debug.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; + +namespace System.Text +{ + public sealed partial class StringBuilder + { + private void ShowChunks(int maxChunksToShow = 10) + { + int count = 0; + StringBuilder head = this, current = this; + while (current != null) + { + if (count < maxChunksToShow) + { + count++; + } + else + { + head = head.m_ChunkPrevious; + } + current = current.m_ChunkPrevious; + } + current = head; + string[] chunks = new string[count]; + for (int i = count; i > 0; i--) + { + chunks[i - 1] = new string(current.m_ChunkChars).Replace('\0', '.'); + current = current.m_ChunkPrevious; + } + Debug.WriteLine('|' + string.Join('|', chunks) + '|'); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs index 185e5a46e..1a3208490 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs @@ -462,13 +462,10 @@ namespace System.Text throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity); } - int originalCapacity = Capacity; - if (value == 0 && m_ChunkPrevious == null) { m_ChunkLength = 0; m_ChunkOffset = 0; - Debug.Assert(Capacity >= originalCapacity); return; } @@ -485,7 +482,10 @@ namespace System.Text { // We crossed a chunk boundary when reducing the Length. We must replace this middle-chunk with a new larger chunk, // to ensure the original capacity is preserved. - int newLen = originalCapacity - chunk.m_ChunkOffset; + + // Avoid possible infinite capacity growth. See https://github.com/dotnet/coreclr/pull/16926 + int capacityToPreserve = Math.Min(Capacity, Math.Max(Length * 6 / 5, m_ChunkChars.Length)); + int newLen = capacityToPreserve - chunk.m_ChunkOffset; char[] newArray = new char[newLen]; Debug.Assert(newLen > chunk.m_ChunkChars.Length, "The new chunk should be larger than the one it is replacing."); @@ -498,7 +498,6 @@ namespace System.Text m_ChunkLength = value - chunk.m_ChunkOffset; AssertInvariants(); } - Debug.Assert(Capacity >= originalCapacity); } } |