From 98a1549622562207910fc3ad572d1e6796969132 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Fri, 25 Nov 2022 23:55:08 +0100 Subject: [PATCH 1/7] do not overallocate SocketAddress.Buffer --- .../Common/src/System/Net/SocketAddress.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index 54b53db82968..f530266ce106 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -92,7 +92,11 @@ public SocketAddress(AddressFamily family, int size) } InternalSize = size; - Buffer = new byte[(size / IntPtr.Size + 2) * IntPtr.Size]; +#if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS + // WSARecvFrom needs a pinned pointer to the size. Allocate 4 extra bytes for it, so we don't need to pin another buffer. + size += 4; +#endif + Buffer = new byte[size]; SocketAddressPal.SetAddressFamily(Buffer, family); } @@ -174,16 +178,17 @@ internal IPEndPoint GetIPEndPoint() // 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; + return Buffer.Length - 4; } public override bool Equals(object? comparand) => From 68153988a92d65dec3b966639a15772b3c61335b Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Sat, 26 Nov 2022 00:12:36 +0100 Subject: [PATCH 2/7] make sure CopyAddressSizeIntoBuffer and GetAddressSizeOffset are only accessible as System.Net.Sockets internals on Windows --- src/libraries/Common/src/System/Net/SocketAddress.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index f530266ce106..17f936c27cb9 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -175,6 +175,7 @@ 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() { @@ -190,6 +191,7 @@ internal int GetAddressSizeOffset() { return Buffer.Length - 4; } +#endif public override bool Equals(object? comparand) => comparand is SocketAddress other && From 7392b08f74da49b32f1c0a0d17894884158d7dfa Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Sat, 26 Nov 2022 01:18:26 +0100 Subject: [PATCH 3/7] use sizeof(int), improve comments --- src/libraries/Common/src/System/Net/SocketAddress.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index 17f936c27cb9..8a1ea3cf0643 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -93,8 +93,9 @@ public SocketAddress(AddressFamily family, int size) InternalSize = size; #if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS - // WSARecvFrom needs a pinned pointer to the size. Allocate 4 extra bytes for it, so we don't need to pin another buffer. - size += 4; + // WSARecvFrom needs a pinned pointer to the 32bit socket address size. + // Allocate extra bytes at the end of Buffer, so we don't need to pin anything else. + size += sizeof(int); #endif Buffer = new byte[size]; @@ -189,7 +190,7 @@ internal void CopyAddressSizeIntoBuffer() // Can be called after the above method did work. internal int GetAddressSizeOffset() { - return Buffer.Length - 4; + return Buffer.Length - sizeof(int); } #endif From ddb50fcecb2baeb8d5215d7e835399a12b984e65 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 30 Nov 2022 01:27:27 +0100 Subject: [PATCH 4/7] add 4-byte alignment --- src/libraries/Common/src/System/Net/SocketAddress.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index 8a1ea3cf0643..a647b5ba5ef5 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -94,8 +94,11 @@ public SocketAddress(AddressFamily family, int size) InternalSize = size; #if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS // WSARecvFrom needs a pinned pointer to the 32bit socket address size. - // Allocate extra bytes at the end of Buffer, so we don't need to pin anything else. - size += sizeof(int); + // Allocate extra bytes at the end of Buffer with a 4-byte alignment, so we don't need to pin anything else. + // The following forumla ensures addition of the minimum necessary extra padding, + // eg. size=16 will be extended to 20, while size=17 will be extended to 24 + const int PtrSize = sizeof(int); + size = (size + PtrSize - 1) / PtrSize * PtrSize + PtrSize; #endif Buffer = new byte[size]; From c62917c6fed83ce8da4d717f4f5d98b69506f22b Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 30 Nov 2022 01:43:15 +0100 Subject: [PATCH 5/7] improve comments --- src/libraries/Common/src/System/Net/SocketAddress.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index a647b5ba5ef5..d942e2293e4a 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -93,10 +93,10 @@ public SocketAddress(AddressFamily family, int size) InternalSize = size; #if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS - // WSARecvFrom needs a pinned pointer to the 32bit socket address size. - // Allocate extra bytes at the end of Buffer with a 4-byte alignment, so we don't need to pin anything else. - // The following forumla ensures addition of the minimum necessary extra padding, - // eg. size=16 will be extended to 20, while size=17 will be extended to 24 + // 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 sizeof(int) extra bytes at the end of Buffer ensuring sizeof(int) alignment for the LPINT lpFromlen pointer, so we don't need to pin anything else. + // The following forumla will extend 'size' to the 4-byte alignment boundary then add 4 more bytes. + // eg. size=16 will be extended to 20, while size=17 will be extended to 24. const int PtrSize = sizeof(int); size = (size + PtrSize - 1) / PtrSize * PtrSize + PtrSize; #endif From 6363fe3eb5284c22f08dc777168265b66435d259 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 30 Nov 2022 02:14:52 +0100 Subject: [PATCH 6/7] always align to IntPtr.Size --- src/libraries/Common/src/System/Net/SocketAddress.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index d942e2293e4a..60bbce7e07f8 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -94,11 +94,9 @@ public SocketAddress(AddressFamily family, int size) InternalSize = 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 sizeof(int) extra bytes at the end of Buffer ensuring sizeof(int) alignment for the LPINT lpFromlen pointer, so we don't need to pin anything else. - // The following forumla will extend 'size' to the 4-byte alignment boundary then add 4 more bytes. - // eg. size=16 will be extended to 20, while size=17 will be extended to 24. - const int PtrSize = sizeof(int); - size = (size + PtrSize - 1) / PtrSize * PtrSize + PtrSize; + // 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 forumla 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]; @@ -193,7 +191,7 @@ internal void CopyAddressSizeIntoBuffer() // Can be called after the above method did work. internal int GetAddressSizeOffset() { - return Buffer.Length - sizeof(int); + return Buffer.Length - IntPtr.Size; } #endif From aceb23f9085026de148725af338f171242a30c50 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 14 Dec 2022 21:17:34 +0100 Subject: [PATCH 7/7] fix typo --- src/libraries/Common/src/System/Net/SocketAddress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index 60bbce7e07f8..2a8de9845014 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -95,7 +95,7 @@ public SocketAddress(AddressFamily family, int 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 forumla will extend 'size' to the alignment boundary then add IntPtr.Size more bytes. + // 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];