Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ internal sealed class LAHashDependentHashTracker

~LAHashDependentHashTracker()
{
if (_dependentHandle.IsAllocated)
_dependentHandle.Free();
_dependentHandle.Dispose();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,7 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50
}
catch
{
if (alpnHandle.IsAllocated)
{
alpnHandle.Free();
}
alpnHandle.Dispose();

throw;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,7 @@ protected override void Dispose(bool disposing)
_writeBio?.Dispose();
}

if (AlpnHandle.IsAllocated)
{
AlpnHandle.Free();
}
AlpnHandle.Dispose();

base.Dispose(disposing);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1664,22 +1664,13 @@ private static void SendError(HttpListenerSession session, ulong requestId, Http
}
finally
{
if (headersArrayHandle.IsAllocated)
{
headersArrayHandle.Free();
}
if (wwwAuthenticateHandle.IsAllocated)
{
wwwAuthenticateHandle.Free();
}
headersArrayHandle.Dispose();
wwwAuthenticateHandle.Dispose();
if (challengeHandles != null)
{
for (int i = 0; i < challengeHandles.Length; i++)
{
if (challengeHandles[i].IsAllocated)
{
challengeHandles[i].Free();
}
challengeHandles[i].Dispose();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,10 +584,7 @@ private void FreePinnedHeaders(List<GCHandle>? pinnedHeaders)
{
foreach (GCHandle gcHandle in pinnedHeaders)
{
if (gcHandle.IsAllocated)
{
gcHandle.Free();
}
gcHandle.Dispose();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,7 @@ internal void ReleasePinnedSendBuffer()
return;
}

if (_pinnedSendBufferHandle.IsAllocated)
{
_pinnedSendBufferHandle.Free();
}
_pinnedSendBufferHandle.Dispose();

_pinnedSendBuffer = ArraySegment<byte>.Empty;
}
Expand Down Expand Up @@ -620,10 +617,7 @@ private bool IsNativeBuffer(IntPtr pBuffer, uint bufferSize)

private void CleanUp()
{
if (_gcHandle.IsAllocated)
{
_gcHandle.Free();
}
_gcHandle.Dispose();

ReleasePinnedSendBuffer();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -896,10 +896,7 @@ private void PinSocketAddressBuffer()
}

// Unpin any existing.
if (_socketAddressGCHandle.IsAllocated)
{
_socketAddressGCHandle.Free();
}
_socketAddressGCHandle.Dispose();

// Pin down the new one.
_socketAddressGCHandle = GCHandle.Alloc(_socketAddress!.Buffer, GCHandleType.Pinned);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,7 @@ public static SocketError Send(SafeSocketHandle handle, IList<ArraySegment<byte>
{
for (int i = 0; i < count; ++i)
{
if (objectsToPin[i].IsAllocated)
{
objectsToPin[i].Free();
}
objectsToPin[i].Dispose();
}
if (!useStack)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ public MemoryHandle(void* pointer, GCHandle handle = default, IPinnable? pinnabl
/// </summary>
public void Dispose()
{
if (_handle.IsAllocated)
{
_handle.Free();
}
_handle.Dispose();

if (_pinnable != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
using Internal.Runtime.CompilerServices;

namespace System.Runtime.InteropServices
Expand All @@ -23,7 +22,7 @@ namespace System.Runtime.InteropServices
/// Pinned - same as Normal, but allows the address of the actual object to be taken.
/// </remarks>
[StructLayout(LayoutKind.Sequential)]
public partial struct GCHandle
public partial struct GCHandle : IDisposable
{
// The actual integer handle value that the EE uses internally.
private IntPtr _handle;
Expand Down Expand Up @@ -67,12 +66,25 @@ private GCHandle(object? value, GCHandleType type)
/// <returns>A new GC handle that protects the object.</returns>
public static GCHandle Alloc(object? value, GCHandleType type) => new GCHandle(value, type);

/// <inheritdoc/>
public void Dispose()
{
IntPtr handle = _handle;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ Can we not Interlocked.Exchange here?

Suggested change
IntPtr handle = _handle;
IntPtr handle = Interlocked.Exchange(ref _handle, IntPtr.Zero);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


if ((nint)handle != 0)
{
_handle = IntPtr.Zero;

InternalFree(GetHandleValue(handle));
}
}

/// <summary>Frees a GC handle.</summary>
public void Free()
{
// Free the handle if it hasn't already been freed.
IntPtr handle = Interlocked.Exchange(ref _handle, IntPtr.Zero);
IntPtr handle = _handle;
ThrowIfInvalid(handle);
_handle = IntPtr.Zero;
InternalFree(GetHandleValue(handle));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,20 +119,60 @@ public void Free_NotInitialized_ThrowsInvalidOperationException()
Assert.Throws<InvalidOperationException>(() => handle.Free());
}

[Fact]
public void Dispose_NotInitialized_DoesntThrow()
{
var handle = new GCHandle();
handle.Dispose();
}

[Fact]
public void Dispose_WorksAsExpected()
{
object target = new object();
GCHandle handle = GCHandle.Alloc(target);

try
{
Assert.Equal(target, handle.Target);
Assert.True(handle.IsAllocated);

handle.Dispose();

Assert.False(handle.IsAllocated);

// Repeated Dispose() calls are just a no-op
handle.Dispose();
handle.Dispose();
handle.Dispose();
handle.Dispose();

Assert.False(handle.IsAllocated);
}
finally
{
handle.Dispose();
Assert.False(handle.IsAllocated);
}
}

public static IEnumerable<object[]> Equals_TestData()
{
GCHandle handle = GCHandle.Alloc(new object());
yield return new object[] { handle, handle, true };
yield return new object[] { GCHandle.Alloc(new object()), GCHandle.Alloc(new object()), false };
// xunit disposes of any IDisposables passed as row values in a member data.
// Avoid GCHandle being disposed of automatically by wrapping it.

yield return new object[] { GCHandle.Alloc(new object()), new object(), false };
yield return new object[] { GCHandle.Alloc(new object()), null, false };
GCHandle handle = GCHandle.Alloc(new object());
yield return new object[] { new KeyValuePair<GCHandle, object>(handle, handle), true };
yield return new object[] { new KeyValuePair<GCHandle, object>(GCHandle.Alloc(new object()), GCHandle.Alloc(new object())), false };
yield return new object[] { new KeyValuePair<GCHandle, object>(GCHandle.Alloc(new object()), new object()), false };
yield return new object[] { new KeyValuePair<GCHandle, object>(GCHandle.Alloc(new object()), null), false };
}

[Theory]
[MemberData(nameof(Equals_TestData))]
public void Equals_Object_ReturnsExpected(GCHandle handle, object other, bool expected)
public void Equals_Object_ReturnsExpected(KeyValuePair<GCHandle, object> pair, bool expected)
{
(GCHandle handle, object other) = pair;
try
{
Assert.Equal(expected, handle.Equals(other));
Expand Down
3 changes: 2 additions & 1 deletion src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13284,14 +13284,15 @@ public sealed partial class FieldOffsetAttribute : System.Attribute
public FieldOffsetAttribute(int offset) { }
public int Value { get { throw null; } }
}
public partial struct GCHandle
public partial struct GCHandle : System.IDisposable
{
private int _dummyPrimitive;
public bool IsAllocated { get { throw null; } }
public object? Target { get { throw null; } set { } }
public System.IntPtr AddrOfPinnedObject() { throw null; }
public static System.Runtime.InteropServices.GCHandle Alloc(object? value) { throw null; }
public static System.Runtime.InteropServices.GCHandle Alloc(object? value, System.Runtime.InteropServices.GCHandleType type) { throw null; }
public void Dispose() { }
public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? o) { throw null; }
public void Free() { }
public static System.Runtime.InteropServices.GCHandle FromIntPtr(System.IntPtr value) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,15 @@ private void FreeNativeOverlapped()
{
for (int i = 0; i < _pinnedData.Length; i++)
{
if (_pinnedData[i].IsAllocated)
{
_pinnedData[i].Free();
}
_pinnedData[i].Dispose();
}
_pinnedData = null;
}

if (_pNativeOverlapped != null)
{
GCHandle handle = *(GCHandle*)(_pNativeOverlapped + 1);
if (handle.IsAllocated)
handle.Free();
handle.Dispose();

Marshal.FreeHGlobal((IntPtr)_pNativeOverlapped);
//CORERT: Interop.MemFree((IntPtr)_pNativeOverlapped);
Expand Down