Repository: dotnet/runtime
File: src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs (C#)

Code before:
                ArrayPool<byte>.Shared.Return(rentedBuffer);
                return new ValueTask(Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.net_io_encrypt, SslStreamPal.GetException(status)))));
            }

            t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);
            if (t.IsCompletedSuccessfully)
            {
                ArrayPool<byte>.Shared.Return(rentedBuffer);
                return t;
            }
            else
            {
                return CompleteWriteAsync(t, rentedBuffer);
            }

            async ValueTask CompleteLockAndWriteAsync(ValueTask t, byte[] bufferToReturn)
            {
                SecurityStatusPal status;
                int encryptedBytes;

                try
                {
                    await t;
                    while (true)
                    {
                        status = EncryptData(buffer, ref outBuffer, out encryptedBytes);
                        if (status.ErrorCode == SecurityStatusPalErrorCode.TryAgain)
                        {
                            TaskCompletionSource<bool>? waiter = _handshakeWaiter;
                            if (waiter != null)
                            {
                                await writeAdapter.LockAsync(waiter);
                            }

                            continue;
                        }
                        else if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
                        {
                            throw new IOException(SR.net_io_encrypt, SslStreamPal.GetException(status));
                        }

                        break;
                    }

                    await writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(bufferToReturn);
                }
            }

Review comment (suggestion):
This local async function is capturing data from the outer function.  I think if you look at the compiled IL, you'll find this is causing allocations even when the async local function is never invoked, e.g. note the display class allocation at the beginning of M here:
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGADAAQY4B0AQgK4Bm9MUAzgNyEnk4CsHBnAMzkspAMKkA3oVKzywjElIBZABQBKKTLk7qATwAuMANoBdUsAZMopALykAglCgBDPQAUIEADYAeYIYwAHyUAMoAFi6wACaUAEowAHYGqjjq/Do6GADspABiXhoZmbLaJRgAHORKBRAaZZnSBCXlAJzVlACaAJYw3tFFDS2Ozm6ePr76RiERUTCxCQa0UImqlozM6UNyAL4NewQ7QA
You should pass in any state you need explicitly (capturing anything other than `this` is likely to cause such behavior); if you want to avoid the possibility of this mistake, make it a normal instance method rather than a local, or if you want to pass in `this` as well, make it a static local function.

Code after:
            ValueTask t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);
            if (t.IsCompletedSuccessfully)
            {
                ArrayPool<byte>.Shared.Return(rentedBuffer);
                return t;
            }
            else
            {
                return CompleteWriteAsync(t, rentedBuffer);
            }

            async ValueTask WaitAndWriteAsync(TIOAdapter writeAdapter, ReadOnlyMemory<byte> buffer, Task waitTask, byte[] rentedBuffer)
            {
                byte[]? bufferToReturn = rentedBuffer;
                byte[] outBuffer = rentedBuffer;
                try
                {
                    // Wait for renegotiation to finish.
                    await waitTask.ConfigureAwait(false);

                    SecurityStatusPal status = EncryptData(buffer, ref outBuffer, out int encryptedBytes);
                    if (status.ErrorCode == SecurityStatusPalErrorCode.TryAgain)
                    {
                        // No need to hold on the buffer any more.
                        ArrayPool<byte>.Shared.Return(bufferToReturn);
                        bufferToReturn = null;
                        // Call WriteSingleChunk() recursively to avoid code duplication.
                        // This should be extremely rare in cases when second renegotiation happens concurrently with Write.
                        await WriteSingleChunk(writeAdapter, buffer).ConfigureAwait(false);
                    }
                    else if (status.ErrorCode == SecurityStatusPalErrorCode.OK)
                    {
                        await writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes).ConfigureAwait(false);
                    }
                    else
                    {
                        throw new IOException(SR.net_io_encrypt, SslStreamPal.GetException(status));
                    }
                }
                finally
                {
                    if (bufferToReturn != null)
                    {
                        ArrayPool<byte>.Shared.Return(bufferToReturn);
                    }
                }
            }

            async ValueTask CompleteWriteAsync(ValueTask writeTask, byte[] bufferToReturn)
            {
                try