mono icon indicating copy to clipboard operation
mono copied to clipboard

SocketTaskExtensions.ReceiveAsync(Memory<T>) always reads zeroes.

Open jduncanator opened this issue 3 years ago • 9 comments

The Memory<T> overload of the SocketTaskExtensions.ReceiveAsync extension method always reads zeroes into the Memory<T>. It should read the bytes read from the network into the Memory<T>.

Steps to Reproduce

  1. Open a Socket
  2. Call the Memory<T> overload of the ReceiveAsync function
  3. Observe it returning the correct amount of bytes read, but reading all zeroes into the Memory<T>.

Taking a look at the Mono implementation of this overload makes the issue pretty obvious.

https://github.com/mono/mono/blob/da11592cbea4269971f4b1f9624769a85cc10660/mcs/class/System/System.Net.Sockets/SocketTaskExtensions.cs#L254-L267

The current implementation creates a copy of the Memory<T> by way of ToArray(), but doesn't store a reference to it. The BeginReceive is essentially reading into a temporary array that is thrown away at the end of the function call, so the result never ends up in the Memory<T>.

jduncanator avatar Mar 06 '21 13:03 jduncanator

Has anyone had a chance to triage this? This is still very much an issue in production for us, preventing us from using a single shared binary between our mobile and desktop targets.

jduncanator avatar May 05 '21 04:05 jduncanator

I met this bug too on unity 2021

frankxii avatar Sep 12 '22 10:09 frankxii

I changed Memory<byte> to ArraySegmen<byte>, solved this problem.

ArraySegment<byte> buffer = new(readBuffer, 0, 1024);
int count = await _socket.ReceiveAsync(buffer, SocketFlags.None);

frankxii avatar Sep 12 '22 11:09 frankxii

I changed Memory to ArraySegmen, solved this problem.

ArraySegment<byte> buffer = new(readBuffer, 0, 1024);
int count = await _socket.ReceiveAsync(buffer, SocketFlags.None);

Reading it into an ArraySegment doesn't really solve this problem, as you're still allocating memory. The idea behind the Memory<T> overload is to avoid a memory allocation. This is no better than just allocating a byte[] and using that to receive into.

jduncanator avatar Sep 26 '22 02:09 jduncanator

Any progress on triaging this? Moderately significant gotcha.

Chicken-Bones avatar Feb 23 '23 09:02 Chicken-Bones

True for Unity 2022.3 😬

AntonPetrov83 avatar Nov 27 '23 08:11 AntonPetrov83

As a solution you can patch this method, here how this was made in one project: https://github.com/openmod/openmod/pull/763

sunnamed434 avatar Feb 16 '24 20:02 sunnamed434

Just tapping back here - apparently this issue doesn't happen on MacOS with Unity 2022.3.22f1

galvesribeiro avatar Jul 04 '24 17:07 galvesribeiro

Re Unity: This is only an issue I saw in 2021.3.29f1. When I tried on 2022.3.36f1 All worked fine. (still and issue with mono 6.12, but Unity folks must've patched it in later releases)

tested with mono 6.12 on Windows 32/64 and macOS: problem is still there!

edit mono repro here: https://github.com/nats-io/nats.net.v2/issues/306#issuecomment-2209240163

mtmk avatar Jul 04 '24 21:07 mtmk