Skip to content

Commit

Permalink
Do not overallocate SocketAddress.Buffer (#78860)
Browse files Browse the repository at this point in the history
* do not overallocate SocketAddress.Buffer
* make sure CopyAddressSizeIntoBuffer and GetAddressSizeOffset are only accessible as System.Net.Sockets internals on Windows
  • Loading branch information
antonfirsov authored Dec 19, 2022
1 parent d260da5 commit 62013d8
Showing 1 changed file with 14 additions and 5 deletions.
19 changes: 14 additions & 5 deletions src/libraries/Common/src/System/Net/SocketAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,13 @@ public SocketAddress(AddressFamily family, int size)
ArgumentOutOfRangeException.ThrowIfLessThan(size, MinSize);

InternalSize = size;
Buffer = new byte[(size / IntPtr.Size + 2) * IntPtr.Size];
#if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS
// WSARecvFrom needs a pinned pointer to the 32bit socket address size: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecvfrom
// Allocate IntPtr.Size extra bytes at the end of Buffer ensuring IntPtr.Size alignment, so we don't need to pin anything else.
// The following formula will extend 'size' to the alignment boundary then add IntPtr.Size more bytes.
size = (size + IntPtr.Size - 1) / IntPtr.Size * IntPtr.Size + IntPtr.Size;
#endif
Buffer = new byte[size];

SocketAddressPal.SetAddressFamily(Buffer, family);
}
Expand Down Expand Up @@ -168,20 +174,23 @@ internal IPEndPoint GetIPEndPoint()
return new IPEndPoint(GetIPAddress(), GetPort());
}

#if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS
// For ReceiveFrom we need to pin address size, using reserved Buffer space.
internal void CopyAddressSizeIntoBuffer()
{
Buffer[Buffer.Length - IntPtr.Size] = unchecked((byte)(InternalSize));
Buffer[Buffer.Length - IntPtr.Size + 1] = unchecked((byte)(InternalSize >> 8));
Buffer[Buffer.Length - IntPtr.Size + 2] = unchecked((byte)(InternalSize >> 16));
Buffer[Buffer.Length - IntPtr.Size + 3] = unchecked((byte)(InternalSize >> 24));
int addressSizeOffset = GetAddressSizeOffset();
Buffer[addressSizeOffset] = unchecked((byte)(InternalSize));
Buffer[addressSizeOffset + 1] = unchecked((byte)(InternalSize >> 8));
Buffer[addressSizeOffset + 2] = unchecked((byte)(InternalSize >> 16));
Buffer[addressSizeOffset + 3] = unchecked((byte)(InternalSize >> 24));
}

// Can be called after the above method did work.
internal int GetAddressSizeOffset()
{
return Buffer.Length - IntPtr.Size;
}
#endif

public override bool Equals(object? comparand) =>
comparand is SocketAddress other &&
Expand Down

0 comments on commit 62013d8

Please sign in to comment.