Summary
os\Socket.receive (and therefore receiveLine / receiveAll) panics with BADF in the Zig socket layer on every read. It affects both TCP and IPC sockets, even when data is available and the peer is still connected. connect and send work fine — only reading is broken.
This currently makes socket reads unusable, and it blocks the socket.listen() item in #63 (which is receive in a fiber).
Reproduction
Start a peer that sends some bytes and stays connected:
python3 -c "import socket,time; s=socket.socket(); s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1); s.bind(('127.0.0.1',8099)); s.listen(1); c,_=s.accept(); c.sendall(b'hello'); time.sleep(2)"
Run this script:
import "buzz:std";
import "buzz:os";
fun main() > void !> any {
final socket = os\Socket.connect(address: "127.0.0.1", port: 8099, netProtocol: .tcp);
final chunk = socket.receive(8);
std\print("recv: {chunk ?? "<null>"}");
socket.close();
}
buzz run-script recv.buzz
Result
thread panic: programmer bug caused syscall error: BADF
std/Io/Threaded.zig:12620 netReadPosix: .BADF => errnoBug(err) // "File descriptor used after closed"
std/Io/net.zig:1305 readVec
std/Io/Reader.zig fill / peekByte / takeByte
src/lib/buzz_os.zig:465 SocketRead (reader.takeByte())
src/vm.zig callNative → ...
Expected: recv: hello.
Notes
- Reproduced three ways: TCP receive-only, IPC (
initIpc) receive-only with the peer held open, and IPC receive after a send. All panic identically, so it's not EOF-, send-, or protocol-specific.
connect + send are confirmed working (a Python server receives the sent bytes), so the fd produced by SocketConnect is valid across native calls — SocketWrite reconstructs a Stream from the same bare fd and writes successfully.
SocketRead (buzz_os.zig:451-465) reconstructs a std.Io.net.Stream from the bare fd and reads through stream.reader(getIo(), buf).interface. The read path hits BADF in Threaded.netReadPosix while the analogous write path does not — so the regression looks specific to how the read stream/reader is built against the threaded Io, rather than the fd being genuinely closed.
- The existing
tests/manual/tcp-client.buzz only ever sends, which is likely why this wasn't caught.
Environment
- buzz
0.6.0-dev (current main)
- Zig 0.16.0
- macOS (aarch64), Darwin 25.5
Summary
os\Socket.receive(and thereforereceiveLine/receiveAll) panics withBADFin the Zig socket layer on every read. It affects both TCP and IPC sockets, even when data is available and the peer is still connected.connectandsendwork fine — only reading is broken.This currently makes socket reads unusable, and it blocks the
socket.listen()item in #63 (which isreceivein a fiber).Reproduction
Start a peer that sends some bytes and stays connected:
python3 -c "import socket,time; s=socket.socket(); s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1); s.bind(('127.0.0.1',8099)); s.listen(1); c,_=s.accept(); c.sendall(b'hello'); time.sleep(2)"Run this script:
Result
Expected:
recv: hello.Notes
initIpc) receive-only with the peer held open, and IPC receive after asend. All panic identically, so it's not EOF-,send-, or protocol-specific.connect+sendare confirmed working (a Python server receives the sent bytes), so the fd produced bySocketConnectis valid across native calls —SocketWritereconstructs aStreamfrom the same bare fd and writes successfully.SocketRead(buzz_os.zig:451-465) reconstructs astd.Io.net.Streamfrom the bare fd and reads throughstream.reader(getIo(), buf).interface. The read path hitsBADFinThreaded.netReadPosixwhile the analogous write path does not — so the regression looks specific to how the read stream/reader is built against the threadedIo, rather than the fd being genuinely closed.tests/manual/tcp-client.buzzonly ever sends, which is likely why this wasn't caught.Environment
0.6.0-dev(currentmain)