From 99a66e3aa59c3ab8910c7dfaf822860b81bdbe4f Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 12 May 2026 17:20:04 +0200 Subject: [PATCH] Make LimitArrayPoolWriteStream.ReturnAllPooledBuffers idempotent Use Interlocked exchanges so that concurrent Dispose() calls cannot double-return the same buffer to ArrayPool.Shared. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/System/Net/Http/HttpContent.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs index 2ee82b8298b82b..00a1f9d31629cd 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs @@ -1077,10 +1077,12 @@ public void CopyToCore(Span destination) private void ReturnAllPooledBuffers() { - if (_pooledBuffers is byte[]?[] buffers) + // Use Interlocked exchanges so that concurrent Dispose() calls cannot + // double-return the same buffer to the pool. Stream.Dispose isn't required + // to be thread-safe, but a buffer returned twice corrupts the shared pool + // process-wide, so we make this method idempotent under racing callers. + if (Interlocked.Exchange(ref _pooledBuffers, null) is byte[]?[] buffers) { - _pooledBuffers = null; - foreach (byte[]? buffer in buffers) { if (buffer is null) @@ -1092,15 +1094,15 @@ private void ReturnAllPooledBuffers() } } - Debug.Assert(_lastBuffer is not null); + // Capture the last buffer reference before claiming the pooled flag. + // Whichever caller wins the bool exchange owns the captured reference; + // losers skip the Return and just clear the field. byte[] lastBuffer = _lastBuffer; - _lastBuffer = null!; - - if (_lastBufferIsPooled) + if (Interlocked.Exchange(ref _lastBufferIsPooled, false)) { - _lastBufferIsPooled = false; ArrayPool.Shared.Return(lastBuffer); } + _lastBuffer = null!; } public override void Write(byte[] buffer, int offset, int count)