Repository: dotnet/runtime
File: src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs (C#)

Code before:
                lock (context._lock)
                {
                    if (context._disposed)
                    {
                        Debug.Write("WriteToConnection: context is disposed");
                        return;
                    }

                    var inputBuffer = new ReadOnlySpan<byte>(data, dataLength);

                    context._outputBuffer.EnsureAvailableSpace(dataLength);
                    inputBuffer.CopyTo(context._outputBuffer.AvailableSpan);
                    context._outputBuffer.Commit(dataLength);
                }
            }
            catch (Exception ex)
            {
                Debug.Write("Exception Caught. - " + ex);
            }
        }

        [UnmanagedCallersOnly]
        private static unsafe PAL_SSLStreamStatus ReadFromConnection(IntPtr connection, byte* data, int* dataLength)
        {
            GCHandle h = GCHandle.FromIntPtr(connection);
            SafeDeleteSslContext? context = h.IsAllocated ? h.Target as SafeDeleteSslContext : null;
            if (context is null)
            {
                Debug.Write("ReadFromConnection: context is null");
                *dataLength = 0;
                return PAL_SSLStreamStatus.Error;
            }

            try
            {
                lock (context._lock)
                {
                    if (context._disposed)
                    {
                        Debug.Write("ReadFromConnection: context is disposed");
                        *dataLength = 0;
                        return PAL_SSLStreamStatus.Error;
                    }

                    int toRead = *dataLength;
                    if (toRead == 0)
                        return PAL_SSLStreamStatus.OK;

                    if (context._inputBuffer.ActiveLength == 0)
                    {
                        *dataLength = 0;

Review comment (bug):
Should this be a `Debug.Assert(h.IsAllocated)` instead?

Is this handle being freed anywhere? Note that weak handles should still be manually freed, even if the object they're pointing at has been collected already.
https://github.com/dotnet/runtime/blob/4525c6db273dd56845f6c854171a3c11d56ed5cc/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs#L295

Code after:
            lock (context._lock)
            {
                if (context._disposed)
                {
                    Debug.Write("WriteToConnection: context is disposed");
                    return;
                }

                var inputBuffer = new ReadOnlySpan<byte>(data, dataLength);

                context._outputBuffer.EnsureAvailableSpace(dataLength);
                inputBuffer.CopyTo(context._outputBuffer.AvailableSpan);
                context._outputBuffer.Commit(dataLength);
            }
        }

        [UnmanagedCallersOnly]
        private static unsafe PAL_SSLStreamStatus ReadFromConnection(IntPtr connection, byte* data, int* dataLength)
        {
            WeakGCHandle<SafeDeleteSslContext> h = WeakGCHandle<SafeDeleteSslContext>.FromIntPtr(connection);
            if (!h.TryGetTarget(out SafeDeleteSslContext? context))
            {
                Debug.Write("ReadFromConnection: failed to get target context");
                *dataLength = 0;
                return PAL_SSLStreamStatus.Error;
            }

            lock (context._lock)
            {
                if (context._disposed)
                {
                    Debug.Write("ReadFromConnection: context is disposed");
                    *dataLength = 0;
                    return PAL_SSLStreamStatus.Error;
                }

                int toRead = *dataLength;
                if (toRead == 0)
                    return PAL_SSLStreamStatus.OK;

                if (context._inputBuffer.ActiveLength == 0)
                {
                    *dataLength = 0;
                    return PAL_SSLStreamStatus.NeedData;
                }

                toRead = Math.Min(toRead, context._inputBuffer.ActiveLength);

                context._inputBuffer.ActiveSpan.Slice(0, toRead).CopyTo(new Span<byte>(data, toRead));
                context._inputBuffer.Discard(toRead);