Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
net: (*UDPConn).ReadFrom with zero-byte buffer does not block #23849
What version of Go are you using (
I'm not a Windows user and have no Windows stuff. Also I don't understand what's the real problem with your description: "Tried to block on a call to net.PacketConn.ReadFrom" because I'm not a mind reader. Can you please show us a minimal, repro code? Thanks.
Hi @mikioh ,
Sure, I will put together some example code to show the issue tomorrow. I have taken a look through the implementation and I will share what I have found so far.
To clarify the expected behaviour, it is my impression that calls like Read, ReadFrom, ReadFromUDP etc should be blocking by default, unless the underlying fd has been modified. This is not what I am seeing though.
Working: UDPConn.Read does block.
Here is the call stack:
Not Working: UDPConn.ReadFrom, UDPConn.ReadFromUDP do not block
Here is the call stack,
It seems that WSARecv blocks as expected, but WSARecvFrom does not. Both end up making the same call to Syscall9, but one specifies the source address and the other does not (I don't think that is significant).
My suspicion lies in the file syscall/zsyscall_windows.go, specifically how it sets up the "overlapping" parameter. It seems that overlapping sockets have different blocking behaviour, as described in this document:
The next step is to compare WSARecv and WSARecvFrom to see the differences in how they are set up. I am not familiar with this code so please take this with a pinch of salt.
With your repro code, please clarify what's meant by your "blocking/non-blocking?" For Go API calls? Windows system service calls? the behavior of Windows transport-layer protocol implementation? If you have a question, the existing test code in the net package might be a help.
When I say "blocking", I mean that the Go API function (in this case ReadFrom) will not return until there is some data to return (unless there is an error or the socket is closed in another goroutine). I expect that this API would be consistent across platforms.
My understanding of the Read and ReadFrom methods is that they should both have this blocking behavior. However, it seems that ReadFrom returns immediately with zero bytes and nil error on Windows.
Here is the minimal code to reproduce this issue on Windows.
Working, blocks forever (since there is no traffic to receive):
Not working, returns immediately with 0 bytes and nil error:
To compare, I ran the same code on Ubuntu 16.04 and I found that the behaviour is reversed! On linux, sock.Read returns immediately with 0 bytes and nil error, but ReadFrom blocks until it is manually killed with Ctrl-C.
If you are asking about the behavior of network IO system calls with "zero-byte user-supplied buffer space", that's not a Go specific question. You may try it with other languages but the most certain way is just to take a look at each operating system kernel's source code; FWIW, the behavior also differs between underlying network- and/or transport-layer protocols.
In short, it depends on each operating system implementation and we now don't try to abstract it because we don't think it's worthy. The test harnesses TestUDPZeroBytePayload and TestUDPZeroByteBuffer in net/udpsock_test.go describe a bit.
Closing. If you want to try to make more abstracted behavior, please open a new issue. Thanks.
Yes, I just realised my mistake here. In my original code I was allocating the buffer like this:
and now I realise that it should be like this:
This was my mistake so I am happy for it to be closed. Thanks for your support in understanding this!