Make LimitArrayPoolWriteStream.ReturnAllPooledBuffers idempotent#128083
Make LimitArrayPoolWriteStream.ReturnAllPooledBuffers idempotent#128083EgorBo wants to merge 1 commit into
Conversation
Use Interlocked exchanges so that concurrent Dispose() calls cannot double-return the same buffer to ArrayPool<byte>.Shared. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Tagging subscribers to this area: @karelz, @dotnet/ncl |
There was a problem hiding this comment.
Pull request overview
This PR makes HttpContent.LimitArrayPoolWriteStream.ReturnAllPooledBuffers() safe to call multiple times concurrently by making buffer-return operations idempotent, preventing accidental double-return of the same byte[] to ArrayPool<byte>.Shared (which can corrupt the shared pool).
Changes:
- Atomically claims and clears
_pooledBuffersviaInterlocked.Exchange(ref _pooledBuffers, null)so only one caller returns the pooled buffer list. - Atomically claims and clears
_lastBufferIsPooledviaInterlocked.Exchange(ref _lastBufferIsPooled, false)so only one caller returns the final pooled buffer. - Updates internal comments to document the rationale and the concurrency/idempotency intent.
|
We could consider having In your example, if you call |
|
I'm not familiar with this logic so I'm leaving it to you. The general idea is that even if users do something stupid (as long as it's not unsafe code) we shouldn't corrupt the global state which ArrayPool is |
Makes
LimitArrayPoolWriteStream.ReturnAllPooledBuffersidempotent under concurrentDispose()so that user code cannot accidentally double-return the same buffer toArrayPool<byte>.Shared. TwoInterlocked.Exchangecalls on the existing fields are enough — no new allocations or fast-path overhead in the single-threaded case.It's not a security issue, just makes code more robust to buggy implementations
Note
This PR was authored with the assistance of GitHub Copilot.