wavefnd / wavefnd/Wave

Keep zero-length TCP reads distinct from stream EOF

Open
#509 0 comments 0 reactions 0 assignees View on GitHub
bug cross-platform good first issue needs testing
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.