commit 1a28643dd849667c1407dfca45f3988185f86c6b
parent 72246984b124e5cab9d9e092d190cbebee97badf
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date: Thu, 17 Sep 2020 15:37:06 +0100
Still have memory corruption errors. Going to rewrite the whole thing to try to avoid any Use-After-Free issues with the ArrayPool, and to avoid any dodgy Memory and Span trickery
Diffstat:
8 files changed, 39 insertions(+), 255 deletions(-)
diff --git a/NetSharp/NetSharp/NetSharp.csproj b/NetSharp/NetSharp/NetSharp.csproj
@@ -75,4 +75,8 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
-</Project>
-\ No newline at end of file
+
+ <ItemGroup>
+ <Folder Include="Deprecated\" />
+ </ItemGroup>
+</Project>
diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml
@@ -493,66 +493,12 @@
Wraps the <see cref="T:System.BitConverter" /> class to provide conversion that is endian-aware.
</summary>
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Boolean,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.Boolean)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Char,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.Char)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Double,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.Double)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Single,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.Single)" />
- </member>
<member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int32,System.Boolean)">
<inheritdoc cref="M:System.BitConverter.GetBytes(System.Int32)" />
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int64,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.Int64)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.Int16,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.Int16)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt32,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt32)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt64,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt64)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.GetBytes(System.UInt16,System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.GetBytes(System.UInt16)" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToBoolean(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToBoolean(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToChar(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToChar(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToDouble(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToDouble(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt16(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToInt16(System.ReadOnlySpan{System.Byte})" />
- </member>
<member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt32(System.Span{System.Byte},System.Boolean)">
<inheritdoc cref="M:System.BitConverter.ToInt32(System.ReadOnlySpan{System.Byte})" />
</member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToInt64(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToInt64(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToSingle(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToSingle(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt16(System.Byte[],System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToUInt16(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt32(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToUInt32(System.ReadOnlySpan{System.Byte})" />
- </member>
- <member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ToUInt64(System.Span{System.Byte},System.Boolean)">
- <inheritdoc cref="M:System.BitConverter.ToUInt64(System.ReadOnlySpan{System.Byte})" />
- </member>
<member name="M:NetSharp.Utils.Conversion.EndianAwareBitConverter.ReverseAsNeeded(System.Span{System.Byte},System.Boolean)">
<summary>
Reverses the given bytes if the endian-nes doesn't match.
diff --git a/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkReader.cs b/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkReader.cs
@@ -80,6 +80,8 @@ namespace NetSharp.Raw.Datagram
SocketAsyncEventArgs instance = new SocketAsyncEventArgs { RemoteEndPoint = DefaultEndPoint };
instance.Completed += HandleIoCompleted;
+ instance.RemoteEndPoint = DefaultEndPoint;
+
return instance;
}
@@ -112,6 +114,8 @@ namespace NetSharp.Raw.Datagram
switch (args.SocketError)
{
case SocketError.Success:
+ byte[] testBuffer = Array.Empty<byte>();
+
byte[] responseBuffer = BufferPool.Rent(datagramSize);
bool responseExists = requestHandler(args.RemoteEndPoint, receiveBuffer, args.BytesTransferred, responseBuffer);
@@ -136,7 +140,12 @@ namespace NetSharp.Raw.Datagram
private void CompleteSendTo(SocketAsyncEventArgs args)
{
- CleanupTransmissionBufferAndState(args);
+ switch (args.SocketError)
+ {
+ default:
+ CleanupTransmissionBufferAndState(args);
+ break;
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/NetSharp/NetSharp/Raw/RawNetworkConnectionBase.cs b/NetSharp/NetSharp/Raw/RawNetworkConnectionBase.cs
@@ -1,5 +1,6 @@
using System;
using System.Buffers;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
@@ -76,33 +77,33 @@ namespace NetSharp.Raw
argsPool = new SlimObjectPool<SocketAsyncEventArgs>(CreateStateObject, ResetStateObject, DestroyStateObject, CanReuseStateObject);
// TODO implement pooling in better way
+ /*
for (uint i = 0; i < preallocatedStateObjects; i++)
{
-#pragma warning disable CA2214 // Nie wywołuj w konstruktorach metod, które można przesłaniać
argsPool.Return(CreateStateObject());
-#pragma warning restore CA2214 // Nie wywołuj w konstruktorach metod, które można przesłaniać
}
+ */
}
/// <summary>
/// The object pool to use to pool <see cref="SocketAsyncEventArgs" /> instances.
/// </summary>
- protected ref readonly SlimObjectPool<SocketAsyncEventArgs> ArgsPool => ref argsPool;
+ protected SlimObjectPool<SocketAsyncEventArgs> ArgsPool => argsPool;
/// <summary>
/// The object pool to use to pool byte buffer instance.
/// </summary>
- protected ref readonly ArrayPool<byte> BufferPool => ref bufferPool;
+ protected ArrayPool<byte> BufferPool => bufferPool;
/// <summary>
/// The underlying connection socket.
/// </summary>
- protected ref readonly Socket Connection => ref connection;
+ protected Socket Connection => connection;
/// <summary>
/// The default endpoint to use to represent remote clients.
/// </summary>
- protected ref readonly EndPoint DefaultEndPoint => ref defaultEndPoint;
+ protected EndPoint DefaultEndPoint => defaultEndPoint;
/// <inheritdoc />
public void Dispose()
@@ -124,16 +125,15 @@ namespace NetSharp.Raw
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected void CleanupTransmissionBufferAndState(SocketAsyncEventArgs args)
{
- if (args != default)
- {
- if (args.Buffer != default)
- {
- bufferPool.Return(args.Buffer, true);
- args.SetBuffer(null, 0, 0);
- }
+ Debug.Assert(args != default, "Attempted to cleanup \'null\' SocketAsyncEventArgs instance!");
- argsPool.Return(args);
+ if (args.Buffer != default)
+ {
+ bufferPool.Return(args.Buffer, true);
+ args.SetBuffer(Array.Empty<byte>(), 0, 0);
}
+
+ argsPool.Return(args);
}
/// <inheritdoc cref="SlimObjectPool{T}.CreateObjectDelegate" />
@@ -151,6 +151,7 @@ namespace NetSharp.Raw
protected virtual void Dispose(bool disposing)
{
ConnectionDisposed = true;
+ Debug.WriteLine("Disposing of NetworkConnectionBase!");
if (disposing)
{
diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkReader.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkReader.cs
@@ -293,7 +293,7 @@ namespace NetSharp.Raw.Stream
byte[] pendingPacketDataBuffer = BufferPool.Rent(receivedPacketHeader.DataSize);
args.SetBuffer(pendingPacketDataBuffer, 0, receivedPacketHeader.DataSize);
- args.UserToken = new PacketReadToken(receivedPacketHeader.DataSize, receivedPacketHeader);
+ args.UserToken = new PacketReadToken(receivedPacketHeader.DataSize);
}
private void ConfigureAsyncReceiveHeader(SocketAsyncEventArgs args)
@@ -303,7 +303,7 @@ namespace NetSharp.Raw.Stream
byte[] pendingPacketHeaderBuffer = BufferPool.Rent(RawStreamPacketHeader.TotalSize);
args.SetBuffer(pendingPacketHeaderBuffer, 0, RawStreamPacketHeader.TotalSize);
- args.UserToken = new PacketReadToken(RawStreamPacketHeader.TotalSize, null);
+ args.UserToken = new PacketReadToken(RawStreamPacketHeader.TotalSize);
}
private void ConfigureAsyncSendPacket(
@@ -389,13 +389,9 @@ namespace NetSharp.Raw.Stream
{
public readonly int BytesToTransfer;
- public readonly RawStreamPacketHeader? Header;
-
- public PacketReadToken(int bytesToTransfer, in RawStreamPacketHeader? header)
+ public PacketReadToken(int bytesToTransfer)
{
BytesToTransfer = bytesToTransfer;
-
- Header = header;
}
}
diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamPacketHeader.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamPacketHeader.cs
@@ -1,7 +1,6 @@
using System;
using System.Runtime.CompilerServices;
-
-using NetSharp.Utils.Conversion;
+using System.Runtime.InteropServices;
namespace NetSharp.Raw.Stream
{
@@ -43,8 +42,7 @@ namespace NetSharp.Raw.Stream
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static RawStreamPacketHeader Deserialise(in Memory<byte> buffer)
{
- Span<byte> serialisedDataSize = buffer.Slice(0, sizeof(int)).Span;
- int dataSize = EndianAwareBitConverter.ToInt32(serialisedDataSize);
+ int dataSize = MemoryMarshal.Read<int>(buffer.Span.Slice(0, sizeof(int)));
return new RawStreamPacketHeader(dataSize);
}
@@ -58,8 +56,9 @@ namespace NetSharp.Raw.Stream
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Serialise(in Memory<byte> buffer)
{
- Span<byte> serialisedDataSize = EndianAwareBitConverter.GetBytes(DataSize);
- serialisedDataSize.CopyTo(buffer.Slice(0, sizeof(int)).Span);
+ int dataSize = DataSize;
+
+ MemoryMarshal.Write(buffer.Span.Slice(0, sizeof(int)), ref dataSize);
}
}
}
diff --git a/NetSharp/NetSharp/Utils/Conversion/EndianAwareBitConverter.cs b/NetSharp/NetSharp/Utils/Conversion/EndianAwareBitConverter.cs
@@ -1,165 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-
-namespace NetSharp.Utils.Conversion
-{
- /// <summary>
- /// Wraps the <see cref="BitConverter" /> class to provide conversion that is endian-aware.
- /// </summary>
- internal static class EndianAwareBitConverter
- {
- /// <inheritdoc cref="BitConverter.GetBytes(bool)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(bool value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(char)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(char value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(double)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(double value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(float)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(float value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(int)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(int value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(long)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(long value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(short)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(short value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(uint)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(uint value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(ulong)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(ulong value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.GetBytes(ushort)" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static Span<byte> GetBytes(ushort value, bool littleEndian = false)
- {
- return ReverseAsNeeded(BitConverter.GetBytes(value), littleEndian);
- }
-
- /// <inheritdoc cref="BitConverter.ToBoolean(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static bool ToBoolean(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToBoolean(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToChar(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static char ToChar(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToChar(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToDouble(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static double ToDouble(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToDouble(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToInt16(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static short ToInt16(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToInt16(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToInt32(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static int ToInt32(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToInt32(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToInt64(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static long ToInt64(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToInt64(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToSingle(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static float ToSingle(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToSingle(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToUInt16(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static ushort ToUInt16(byte[] bytes, bool littleEndian = false)
- {
- return BitConverter.ToUInt16(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToUInt32(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static uint ToUInt32(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToUInt32(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <inheritdoc cref="BitConverter.ToUInt64(ReadOnlySpan{byte})" />
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static ulong ToUInt64(Span<byte> bytes, bool littleEndian = false)
- {
- return BitConverter.ToUInt64(ReverseAsNeeded(bytes, littleEndian));
- }
-
- /// <summary>
- /// Reverses the given bytes if the endian-nes doesn't match.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Span<byte> ReverseAsNeeded(Span<byte> bytes, bool toLittleEndian)
- {
- if (toLittleEndian != BitConverter.IsLittleEndian)
- {
- bytes.Reverse();
- }
-
- return bytes;
- }
- }
-}
diff --git a/NetSharp/NetSharp/Utils/SlimObjectPool.cs b/NetSharp/NetSharp/Utils/SlimObjectPool.cs
@@ -110,12 +110,7 @@ namespace NetSharp.Utils
{
bool successfullyRentedInstance = objectBuffer.TryTake(out T instance);
- if (successfullyRentedInstance)
- {
- return instance;
- }
-
- return createObjectDelegate();
+ return successfullyRentedInstance ? instance : createObjectDelegate();
}
/// <summary>