记录 Zig 0.16 Net 标准库在 Windows 上的 Bug

今天在学习使用 Zig 编写 Tcp 程序,遇到了一个只在 Windows 平台出现、Linux 平台完全正常的标准库 Bug。

代码如下:

zig
const std = @import("std");

pub fn main(init: std.process.Init) !void {
    const addr = try std.Io.net.IpAddress.parse("127.0.0.1", 3000);

    var server = try addr.listen(init.io, .{});
    defer server.deinit(init.io);

    std.debug.print("[Info] listen 127.0.0.1:3000\n", .{});

    while (server.accept(init.io)) |stream| {
        std.debug.print("[Info] accept {}\n", .{stream.socket.address});
        _ = std.Thread.spawn(.{}, handleConnect, .{ init.io, stream }) catch |err| {
            stream.close(init.io);
            std.debug.print("[Error] Thread.spawn error: {}\n", .{err});
        };
    } else |err| {
        return err;
    }
}

fn handleConnect(io: std.Io, stream: std.Io.net.Stream) !void {
    defer stream.close(io);

    var buf: [4096]u8 = undefined;
    const msg = try stream.socket.receive(io, &buf);

    std.debug.print("[Info] client message: {s}\n", .{msg.data});
}

问题出在这一行:

zig
const msg = try stream.socket.receive(io, &buf);

在 Windows 平台调用时,会直接返回错误:

error.Unexpected NTSTATUS=0xc000000d (INVALID_PARAMETER)

一开始我以为是我调用方式有问题,于是换了另一种写法:

zig
fn handleConnect(io: std.Io, stream: std.Io.net.Stream) !void {
    defer stream.close(io);

    // var buf: [4096]u8 = undefined;
    // const msg = try stream.socket.receive(io, &buf);

    // std.debug.print("[Info] client message: {s}\n", .{msg.data});

    var reader_buf: [4096]u8 = undefined;
    var reader = stream.reader(io, &reader_buf);

    var buf: [4096]u8 = undefined;
    var writer = std.Io.Writer.fixed(&buf);
    try reader.interface.streamExact(&writer, 10);

    std.debug.print("[Info] client message: {s}\n", .{writer.buffered()});
}

使用上面的调用方式,就可以正常的获取客户端发送的消息了。但是这个调用方式只是用 Reader 包装了一下,其他基本逻辑是没有变化的。

所以我开始怀疑是不是 stream.socket.receive 这个函数的实现有 Bug。毕竟这个函数的使用方式是那么简单,提供一个缓冲区,用于接收客户端发送过来的数据,几乎不存在误用的可能。而新的调用方式也证明了我的其他代码逻辑是没有问题的,可以正常接收客户端数据。

我将相同的代码交叉编译为 Linux 版本,并部署到 Linux 环境中进行测试。结果非常完美,相同的代码,在 Linux 上可以正常工作,但是到 Windows 就会报错,我可以确定,这就是 Zig 0.16 标准库在 Windows 的实现 Bug。