Skip to content

Commit c39954c

Browse files
Throttle allocations in BinaryReader (#36348) (#36427)
1 parent ea2a26b commit c39954c

File tree

3 files changed

+35
-23
lines changed

3 files changed

+35
-23
lines changed

src/libraries/Common/src/System/Text/StringBuilderCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal static class StringBuilderCache
1111
// The value 360 was chosen in discussion with performance experts as a compromise between using
1212
// as litle memory per thread as possible and still covering a large part of short-lived
1313
// StringBuilder creations on the startup path of VS designers.
14-
private const int MaxBuilderSize = 360;
14+
internal const int MaxBuilderSize = 360;
1515
private const int DefaultCapacity = 16; // == StringBuilder.DefaultCapacity
1616

1717
// WARNING: We allow diagnostic tools to directly inspect this member (t_cachedInstance).

src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,10 @@ public virtual string ReadString()
306306
return new string(_charBuffer, 0, charsRead);
307307
}
308308

309-
sb ??= StringBuilderCache.Acquire(stringLength); // Actual string length in chars may be smaller.
309+
// Since we could be reading from an untrusted data source, limit the initial size of the
310+
// StringBuilder instance we're about to get or create. It'll expand automatically as needed.
311+
312+
sb ??= StringBuilderCache.Acquire(Math.Min(stringLength, StringBuilderCache.MaxBuilderSize)); // Actual string length in chars may be smaller.
310313
sb.Append(_charBuffer, 0, charsRead);
311314
currPos += n;
312315
} while (currPos < stringLength);

src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -213,28 +213,37 @@ private bool TryEnsureBytes(int count)
213213
{
214214
if (_stream == null)
215215
return false;
216-
DiagnosticUtility.DebugAssert(_offset <= int.MaxValue - count, "");
217-
int newOffsetMax = _offset + count;
218-
if (newOffsetMax < _offsetMax)
219-
return true;
220-
DiagnosticUtility.DebugAssert(newOffsetMax <= _windowOffsetMax, "");
221-
if (newOffsetMax > _buffer.Length)
222-
{
223-
byte[] newBuffer = new byte[Math.Max(newOffsetMax, _buffer.Length * 2)];
224-
System.Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _offsetMax);
225-
_buffer = newBuffer;
226-
_streamBuffer = newBuffer;
227-
}
228-
int needed = newOffsetMax - _offsetMax;
229-
while (needed > 0)
216+
217+
// The data could be coming from an untrusted source, so we use a standard
218+
// "multiply by 2" growth algorithm to avoid overly large memory utilization.
219+
// Constant value of 256 comes from MemoryStream implementation.
220+
221+
do
230222
{
231-
int actual = _stream.Read(_buffer, _offsetMax, needed);
232-
if (actual == 0)
233-
return false;
234-
_offsetMax += actual;
235-
needed -= actual;
236-
}
237-
return true;
223+
DiagnosticUtility.DebugAssert(_offset <= int.MaxValue - count, "");
224+
int newOffsetMax = _offset + count;
225+
if (newOffsetMax <= _offsetMax)
226+
return true;
227+
DiagnosticUtility.DebugAssert(newOffsetMax <= _windowOffsetMax, "");
228+
if (newOffsetMax > _buffer.Length)
229+
{
230+
byte[] newBuffer = new byte[Math.Max(256, _buffer.Length * 2)];
231+
System.Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _offsetMax);
232+
newOffsetMax = Math.Min(newOffsetMax, newBuffer.Length);
233+
_buffer = newBuffer;
234+
_streamBuffer = newBuffer;
235+
}
236+
int needed = newOffsetMax - _offsetMax;
237+
DiagnosticUtility.DebugAssert(needed > 0, "");
238+
do
239+
{
240+
int actual = _stream.Read(_buffer, _offsetMax, needed);
241+
if (actual == 0)
242+
return false;
243+
_offsetMax += actual;
244+
needed -= actual;
245+
} while (needed > 0);
246+
} while (true);
238247
}
239248

240249
public void Advance(int count)

0 commit comments

Comments
 (0)