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

Code before:
            if (disposing && !_disposed)
            {
                _disposed = true;

                lock (_lock)
                {
                    _inputBuffer.Dispose();
                    _outputBuffer.Dispose();
                    _sslContext.Dispose();
                }

                if (_gcHandle.IsAllocated)
                {
                    _gcHandle.Free();
                }
            }

            base.Dispose(disposing);
        }

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

            try
            {
                lock (context._lock)
                {
                    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)
        {

Review comment (bug):
If the handle was not freed yet, there's a race here - the check to disposed may return false here, but by the time we take the lock below, the dispose has already happened and we'll end up in the same spot as before the bugfix.

Code after:
                if (!_disposed)
                {
                    _disposed = true;

                    // First dispose the SSL context to trigger native cleanup
                    _sslContext.Dispose();

                    if (disposing)
                    {
                        // Then dispose the buffers
                        _inputBuffer.Dispose();
                        _outputBuffer.Dispose();
                    }
                }
            }

            base.Dispose(disposing);
        }

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

            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))
            {