Keep zero-length TCP reads distinct from stream EOF
- Dominant language
- Rust
- Stars
- 53
- Forks
- 16
- Avg merge
- 4h 22m
- Merged PRs (30d)
- 46
Description
## Reproduced problem
`tcp_read_result` maps every zero return to EOF, including a read whose requested size is zero. `tcp_read_vectored` reaches the same behavior when it receives one or more slices whose total capacity is zero.
On an open Linux loopback TCP connection with a byte already queued, these calls report `count=0 eof=1 error=10`, even though the peer has not shut down and the queued byte remains readable:
```wave
import("std::net::tcp")::{TcpStream, tcp_read_result};
import("std::net::error")::{NetIoResult};
import("std::net::vectored")::{NetIoSlice, net_recv_vectored};
fun main() -> i32 {
var one: NetIoResult = tcp_read_result(TcpStream { fd: 3 }, null, 0);
var slices: array = [NetIoSlice { data: null, length: 0 }];
var many: NetIoResult = net_recv_vectored(3, &slices[0], 1, 0, true);
println("single={} vector={}", one.eof, many.eof);
return 0;
}
```
For reproduction, create a loopback listener/client pair in Python, queue `b"x"` from the accepted peer, substitute the client's actual descriptor for `3`, compile the source, and execute the binary with `subprocess.run(..., pass_fds=(client.fileno(),))`. After it exits, the Python client still receives `b"x"`. Both Wave EOF fields are currently true. No external network is needed.
## Scope and acceptance
- [ ] A valid zero-length stream read returns a successful zero-byte result without claiming peer EOF or blocking for readability.
- [ ] Handle an empty slice list and a nonempty list of all-zero-length slices consistently.
- [ ] Preserve invalid-size/pointer diagnostics and positive-capacity EOF behavior.
- [ ] Add a local connection regression that proves queued bytes are not consumed and positive-size reads still distinguish data from shutdown.
- [ ] Preserve zero-byte UDP datagram behavior; stream short-circuiting must not suppress receipt of actual datagrams.
Start with `std/net/tcp.wave:334`, `std/net/vectored.wave::net_recv_vectored`, and compare the existing zero-length handling in `tcp_read_timeout` and `net_recv_exact_io`. This is a bounded good first issue.
Audited on canonical master `0c67f4cc0c3946cbf708c11ef79db927ec8f054e` (same source tree as #502 head). Executable reproductions used Fedora Linux amd64, Wave `0.2.1-pre-beta-dev`, LLVM 21.1.8.
Contributor guide
Research direction
Start at std/net/tcp.wave:334 and std/net/vectored.wave::net_recv_vectored; compare their zero-length paths with tcp_read_timeout and net_recv_exact_io. Run the local Python loopback reproduction first, then add the connection regression described in the acceptance criteria. Done means zero-capacity stream reads report success without EOF or blocking, while positive-capacity reads and zero-byte UDP datagrams retain their existing behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- linux, python
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100