Segmentation fault when reading data from a socket using std.Io

I’m trying to use the new std.Io networking code to accept network connections. I am new to Zig & C programming, but not programming in general. The program I am writing consistently crashes with a segmentation fault when attempting to read data from a reader. I have tried running the code on Windows 11 and Ubuntu 22.

const std = @import("std");
const Io = std.Io;
const print = std.debug.print;

pub fn main(init: std.process.Init) !void {
    const io = init.io;
    const address = try Io.net.IpAddress.parseIp4("127.0.0.1", 8080);
    var server = try Io.net.IpAddress.listen(address, io, .{ .reuse_address = true });
    while (true) {
        var stream = try server.accept(io);
        var read_buffer: [1024]u8 = undefined;
        var rdr = stream.reader(io, &read_buffer).interface;
        _ = try rdr.peek(1); <-- Segmentation fault here
    }
}

I’m running zig-x86_64-linux-0.16.0-dev.2905+5d71e3051, but have experienced the same issue with other 0.16.0-dev “releases.” For reference, the stack trace is

Segmentation fault at address 0x728
/home/ryanj/code/zig/zig-x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/std/Io/net.zig:1281:40: 0x11dc7f0 in readVec (std.zig)
const n = io.vtable.netRead(io.userdata, r.stream.socket.handle, dest) catch |err| {
^
/home/ryanj/code/zig/zig-x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/std/Io/Reader.zig:1124:56: 0x1031460 in fillUnbuffered (std.zig)
while (r.end < r.seek + n) _ = try r.vtable.readVec(r, &bufs);
^
/home/ryanj/code/zig/zig-x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/std/Io/Reader.zig:1110:26: 0x10311e8 in fill (std.zig)
return fillUnbuffered(r, n);
^
/home/ryanj/code/zig/zig-x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/std/Io/Reader.zig:511:15: 0x10a7a8b in peek (std.zig)
try r.fill(n);
^
/home/ryanj/code/zig/project/src/main.zig:14:25: 0x11d60f2 in main (main.zig)
_ = try rdr.peek(1);
^
/home/ryanj/code/zig/zig-x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/std/start.zig:716:30: 0x11d6bef in callMain (std.zig)
return wrapMain(root.main(.{
^
/home/ryanj/code/zig/zig-x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/std/start.zig:190:5: 0x11d5d41 in _start (std.zig)
asm volatile (switch (native_arch) {

Any help or guidance would be greatly appreciated.

Your problem is here. You are creating a copy of the interface, not getting a pointer to the stream reader’s interface variable. The details have been discussed in many other threads (namely Zig 0.15.1 reader/writer: Don't make copies of @fieldParentPtr()-based interfaces). You can read that if you want more detailed discussion.

In short, your fix is to capture the Stream.Reader in a variable and get the interface by pointer.

const std = @import("std");
const Io = std.Io;
const print = std.debug.print;

pub fn main(init: std.process.Init) !void {
    const io = init.io;
    const address = try Io.net.IpAddress.parseIp4("127.0.0.1", 8080);
    var server = try Io.net.IpAddress.listen(address, io, .{ .reuse_address = true });
    while (true) {
        var stream = try server.accept(io);
        var read_buffer: [1024]u8 = undefined;
        var stream_reader = stream.reader(io, &read_buffer);
        var rdr = &stream_reader.interface;
        _ = try rdr.peek(1);
        // The following also works
        _ = try stream_reader.interface.peek(1);
    }
}