In https://github.com/dotnet/coreclr/issues/4514 I had reported that StringBuilder.Append(char, int) can fail mid-way causing a partial update to be made. The team decided to fix this but today I discovered that the fix does not quite work.
In particular the capacity check succeeds but the allocation of a new block fails. .NET char arrays are limited to 0x7FEFFFFF elements. That way an allocation of a block can fail even though the argument validation succeeded.
var sb = new StringBuilder();
sb.Append('x', 2);
sb.Length--;
Console.WriteLine($"Length: {sb.Length}, Capacity: {sb.Capacity}, MaxCapacity: {sb.MaxCapacity}");
try
{
sb.Append('x', Int32.MaxValue - 1);
Console.WriteLine($"Length: {sb.Length}, Capacity: {sb.Capacity}, MaxCapacity: {sb.MaxCapacity}");
}
catch (Exception ex)
{
Console.WriteLine(ex); //Expected.
}
Console.WriteLine($"Length: {sb.Length}, Capacity: {sb.Capacity}, MaxCapacity: {sb.MaxCapacity}");
Console.WriteLine(sb.ToString()); //Prints "xxxxxxxxxxxxxxxx", should print "x".
Int32.MaxValue is correctly caught by validation but Int32.MaxValue - 1 is not.
I don't quite know what the right fix is. ExpandByABlock should never be called with a min block size that is greater than the max supported array size.
In https://github.com/dotnet/coreclr/issues/4514 I had reported that StringBuilder.Append(char, int) can fail mid-way causing a partial update to be made. The team decided to fix this but today I discovered that the fix does not quite work.
In particular the capacity check succeeds but the allocation of a new block fails. .NET char arrays are limited to 0x7FEFFFFF elements. That way an allocation of a block can fail even though the argument validation succeeded.
Int32.MaxValueis correctly caught by validation butInt32.MaxValue - 1is not.I don't quite know what the right fix is.
ExpandByABlockshould never be called with a min block size that is greater than the max supported array size.