authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-20 14:20:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:27-07:00
logd7b081882a9dcfff68d2b5a3fb4fcdec8cb74e4b
tree0f29c69d9fc9ef6ed2ca323cb59b9170c39b7983
parente9fd9798f4d6e3cc5af6179881e0323f983095b5

std.net.Stream: fix interface() infinite recursion


1 files changed, 239 insertions(+), 238 deletions(-)

lib/std/net.zig+239-238
...@@ -1829,276 +1829,277 @@ pub const Stream = struct {...@@ -1829,276 +1829,277 @@ pub const Stream = struct {
1829 }1829 }
1830 }1830 }
18311831
1832 pub const Reader = struct {1832 const ReadError = posix.ReadError;
1833 impl: switch (native_os) {1833
1834 .windows => Stream,1834 const WriteError = posix.SendMsgError || error{
1835 else => struct {1835 ConnectionResetByPeer,
1836 fr: std.fs.File.Reader,1836 SocketNotBound,
1837 err: Error!void,1837 MessageTooBig,
1838 },1838 NetworkSubsystemFailed,
1839 },1839 SystemResources,
1840 SocketNotConnected,
1841 Unexpected,
1842 };
18401843
1841 pub const Error = posix.ReadError;1844 pub const Reader = switch (native_os) {
1845 .windows => struct {
1846 stream: Stream,
1847 err: ?Error = null,
18421848
1843 pub fn interface(r: *Reader) std.io.Reader {1849 pub const Error = ReadError;
1844 return switch (native_os) {1850
1845 .windows => .{1851 pub fn interface(r: *Reader) std.io.Reader {
1846 .context = r.impl.stream.handle,1852 return .{
1853 .context = r.stream.handle,
1847 .vtable = &.{1854 .vtable = &.{
1848 .read = windows_read,1855 .read = read,
1849 .readVec = windows_readVec,1856 .readVec = readVec,
1850 .discard = windows_discard,1857 .discard = discard,
1851 },1858 },
1852 },1859 };
1853 else => r.interface(),1860 }
1854 };
1855 }
18561861
1857 fn windows_read(1862 fn read(
1858 context: ?*anyopaque,1863 context: ?*anyopaque,
1859 bw: *std.io.BufferedWriter,1864 bw: *std.io.BufferedWriter,
1860 limit: std.io.Reader.Limit,1865 limit: std.io.Reader.Limit,
1861 ) std.io.Reader.Error!usize {1866 ) std.io.Reader.Error!usize {
1862 const buf = limit.slice(try bw.writableSliceGreedy(1));1867 const buf = limit.slice(try bw.writableSliceGreedy(1));
1863 const status = try windows_readVec(context, &.{buf});1868 const status = try readVec(context, &.{buf});
1864 bw.advance(status.len);1869 bw.advance(status.len);
1865 return status;1870 return status;
1866 }1871 }
18671872
1868 fn windows_readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {1873 fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
1869 var iovecs: [max_buffers_len]windows.WSABUF = undefined;1874 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1870 var iovecs_i: usize = 0;1875 var iovecs_i: usize = 0;
1871 for (data) |d| {1876 for (data) |d| {
1872 // In case Windows checks pointer address before length, we must omit1877 // In case Windows checks pointer address before length, we must omit
1873 // length-zero vectors.1878 // length-zero vectors.
1874 if (d.len == 0) continue;1879 if (d.len == 0) continue;
1875 iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len };1880 iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len };
1876 iovecs_i += 1;1881 iovecs_i += 1;
1877 if (iovecs_i >= iovecs.len) break;1882 if (iovecs_i >= iovecs.len) break;
1883 }
1884 const bufs = iovecs[0..iovecs_i];
1885 if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`.
1886 var n: u32 = undefined;
1887 var flags: u32 = 0;
1888 const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null);
1889 if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) {
1890 .WSAECONNRESET => return error.ConnectionResetByPeer,
1891 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1892 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1893 .WSAEINVAL => return error.SocketNotBound,
1894 .WSAEMSGSIZE => return error.MessageTooBig,
1895 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1896 .WSAENETRESET => return error.ConnectionResetByPeer,
1897 .WSAENOTCONN => return error.SocketNotConnected,
1898 .WSAEWOULDBLOCK => return error.WouldBlock,
1899 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1900 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1901 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1902 else => |err| return windows.unexpectedWSAError(err),
1903 };
1904 return .{ .len = n, .end = n == 0 };
1878 }1905 }
1879 const bufs = iovecs[0..iovecs_i];
1880 if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`.
1881 var n: u32 = undefined;
1882 var flags: u32 = 0;
1883 const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null);
1884 if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) {
1885 .WSAECONNRESET => return error.ConnectionResetByPeer,
1886 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1887 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1888 .WSAEINVAL => return error.SocketNotBound,
1889 .WSAEMSGSIZE => return error.MessageTooBig,
1890 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1891 .WSAENETRESET => return error.ConnectionResetByPeer,
1892 .WSAENOTCONN => return error.SocketNotConnected,
1893 .WSAEWOULDBLOCK => return error.WouldBlock,
1894 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1895 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1896 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1897 else => |err| return windows.unexpectedWSAError(err),
1898 };
1899 return .{ .len = n, .end = n == 0 };
1900 }
19011906
1902 fn windows_discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {1907 fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
1903 _ = context;1908 _ = context;
1904 _ = limit;1909 _ = limit;
1905 @panic("TODO");1910 @panic("TODO");
1906 }1911 }
1907 };1912 },
1913 else => struct {
1914 file_reader: std.fs.File.Reader,
1915
1916 pub const Error = ReadError;
19081917
1909 pub const Writer = struct {1918 pub fn interface(r: *Reader) std.io.Reader {
1910 impl: switch (native_os) {1919 return r.file_reader.interface();
1911 .windows => Stream,1920 }
1912 else => PosixImpl,
1913 },1921 },
1922 };
19141923
1915 const PosixImpl = struct {1924 pub const Writer = switch (native_os) {
1916 fw: std.fs.File.Writer,1925 .windows => struct {
1917 err: Error!void,1926 stream: Stream,
1918 };
19191927
1920 pub const Error = posix.SendMsgError || error{1928 pub const Error = WriteError;
1921 ConnectionResetByPeer,
1922 SocketNotBound,
1923 MessageTooBig,
1924 NetworkSubsystemFailed,
1925 SystemResources,
1926 SocketNotConnected,
1927 Unexpected,
1928 };
19291929
1930 pub fn interface(w: *Writer) std.io.Writer {1930 pub fn interface(w: *Writer) std.io.Writer {
1931 return switch (native_os) {1931 return .{
1932 .windows => .{1932 .context = w.stream.handle,
1933 .context = w.impl.stream.handle,
1934 .vtable = &.{1933 .vtable = &.{
1935 .writeSplat = windows_writeSplat,1934 .writeSplat = writeSplat,
1936 .writeFile = windows_writeFile,1935 .writeFile = writeFile,
1937 },1936 },
1938 },1937 };
1939 else => .{1938 }
1940 .context = &w.impl,1939
1940 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
1941 comptime assert(native_os == .windows);
1942 if (data.len == 1 and splat == 0) return 0;
1943 var splat_buffer: [256]u8 = undefined;
1944 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1945 var len: u32 = @min(iovecs.len, data.len);
1946 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
1947 .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ?
1948 .len = d.len,
1949 };
1950 switch (splat) {
1951 0 => len -= 1,
1952 1 => {},
1953 else => {
1954 const pattern = data[data.len - 1];
1955 if (pattern.len == 1) {
1956 const memset_len = @min(splat_buffer.len, splat);
1957 const buf = splat_buffer[0..memset_len];
1958 @memset(buf, pattern[0]);
1959 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
1960 var remaining_splat = splat - buf.len;
1961 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
1962 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
1963 remaining_splat -= splat_buffer.len;
1964 len += 1;
1965 }
1966 if (remaining_splat > 0 and len < iovecs.len) {
1967 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
1968 len += 1;
1969 }
1970 }
1971 },
1972 }
1973 var n: u32 = undefined;
1974 const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null);
1975 if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) {
1976 .WSAECONNABORTED => return error.ConnectionResetByPeer,
1977 .WSAECONNRESET => return error.ConnectionResetByPeer,
1978 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1979 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1980 .WSAEINVAL => return error.SocketNotBound,
1981 .WSAEMSGSIZE => return error.MessageTooBig,
1982 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1983 .WSAENETRESET => return error.ConnectionResetByPeer,
1984 .WSAENOBUFS => return error.SystemResources,
1985 .WSAENOTCONN => return error.SocketNotConnected,
1986 .WSAENOTSOCK => unreachable, // not a socket
1987 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets
1988 .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown
1989 .WSAEWOULDBLOCK => return error.WouldBlock,
1990 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1991 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1992 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1993 else => |err| return windows.unexpectedWSAError(err),
1994 };
1995 return n;
1996 }
1997
1998 fn writeFile(
1999 context: *anyopaque,
2000 in_file: std.fs.File,
2001 in_offset: u64,
2002 in_len: std.io.Writer.FileLen,
2003 headers_and_trailers: []const []const u8,
2004 headers_len: usize,
2005 ) std.io.Writer.FileError!usize {
2006 const len_int = switch (in_len) {
2007 .zero => return writeSplat(context, headers_and_trailers, 1),
2008 .entire_file => std.math.maxInt(usize),
2009 else => in_len.int(),
2010 };
2011 if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1);
2012 var file_contents_buffer: [4096]u8 = undefined;
2013 const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)];
2014 const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset);
2015 return writeSplat(context, &.{read_buffer[0..n]}, 1);
2016 }
2017 },
2018 else => struct {
2019 file_writer: std.fs.File.Writer,
2020 err: ?Error = null,
2021
2022 pub const Error = WriteError;
2023
2024 pub fn interface(w: *Writer) std.io.Writer {
2025 return .{
2026 .context = &w.file_writer,
1941 .vtable = &.{2027 .vtable = &.{
1942 .writeSplat = posix_writeSplat,2028 .writeSplat = writeSplat,
1943 .writeFile = std.fs.File.Writer.writeFile,2029 .writeFile = std.fs.File.Writer.writeFile,
1944 },2030 },
1945 },2031 };
1946 };
1947 }
1948
1949 fn windows_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
1950 comptime assert(native_os == .windows);
1951 if (data.len == 1 and splat == 0) return 0;
1952 var splat_buffer: [256]u8 = undefined;
1953 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1954 var len: u32 = @min(iovecs.len, data.len);
1955 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
1956 .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ?
1957 .len = d.len,
1958 };
1959 switch (splat) {
1960 0 => len -= 1,
1961 1 => {},
1962 else => {
1963 const pattern = data[data.len - 1];
1964 if (pattern.len == 1) {
1965 const memset_len = @min(splat_buffer.len, splat);
1966 const buf = splat_buffer[0..memset_len];
1967 @memset(buf, pattern[0]);
1968 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
1969 var remaining_splat = splat - buf.len;
1970 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
1971 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
1972 remaining_splat -= splat_buffer.len;
1973 len += 1;
1974 }
1975 if (remaining_splat > 0 and len < iovecs.len) {
1976 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
1977 len += 1;
1978 }
1979 }
1980 },
1981 }2032 }
1982 var n: u32 = undefined;
1983 const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null);
1984 if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) {
1985 .WSAECONNABORTED => return error.ConnectionResetByPeer,
1986 .WSAECONNRESET => return error.ConnectionResetByPeer,
1987 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1988 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1989 .WSAEINVAL => return error.SocketNotBound,
1990 .WSAEMSGSIZE => return error.MessageTooBig,
1991 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1992 .WSAENETRESET => return error.ConnectionResetByPeer,
1993 .WSAENOBUFS => return error.SystemResources,
1994 .WSAENOTCONN => return error.SocketNotConnected,
1995 .WSAENOTSOCK => unreachable, // not a socket
1996 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets
1997 .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown
1998 .WSAEWOULDBLOCK => return error.WouldBlock,
1999 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
2000 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
2001 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
2002 else => |err| return windows.unexpectedWSAError(err),
2003 };
2004 return n;
2005 }
20062033
2007 fn posix_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {2034 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
2008 const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context));2035 const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context));
2009 const impl: *PosixImpl = @fieldParentPtr("fw", fw);2036 const w: *Writer = @fieldParentPtr("file_writer", fw);
2010 comptime assert(native_os != .windows);2037 var splat_buffer: [256]u8 = undefined;
2011 var splat_buffer: [256]u8 = undefined;2038 var iovecs: [max_buffers_len]std.posix.iovec_const = undefined;
2012 var iovecs: [max_buffers_len]std.posix.iovec_const = undefined;2039 var len: usize = @min(iovecs.len, data.len);
2013 var len: usize = @min(iovecs.len, data.len);2040 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
2014 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{2041 .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length.
2015 .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length.2042 .len = d.len,
2016 .len = d.len,2043 };
2017 };2044 var msg: posix.msghdr_const = .{
2018 var msg: posix.msghdr_const = .{2045 .name = null,
2019 .name = null,2046 .namelen = 0,
2020 .namelen = 0,2047 .iov = &iovecs,
2021 .iov = &iovecs,2048 .iovlen = len,
2022 .iovlen = len,2049 .control = null,
2023 .control = null,2050 .controllen = 0,
2024 .controllen = 0,2051 .flags = 0,
2025 .flags = 0,2052 };
2026 };2053 switch (splat) {
2027 switch (splat) {2054 0 => msg.iovlen = len - 1,
2028 0 => msg.iovlen = len - 1,2055 1 => {},
2029 1 => {},2056 else => {
2030 else => {2057 const pattern = data[data.len - 1];
2031 const pattern = data[data.len - 1];2058 if (pattern.len == 1) {
2032 if (pattern.len == 1) {2059 const memset_len = @min(splat_buffer.len, splat);
2033 const memset_len = @min(splat_buffer.len, splat);2060 const buf = splat_buffer[0..memset_len];
2034 const buf = splat_buffer[0..memset_len];2061 @memset(buf, pattern[0]);
2035 @memset(buf, pattern[0]);2062 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
2036 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };2063 var remaining_splat = splat - buf.len;
2037 var remaining_splat = splat - buf.len;2064 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
2038 while (remaining_splat > splat_buffer.len and len < iovecs.len) {2065 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
2039 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };2066 remaining_splat -= splat_buffer.len;
2040 remaining_splat -= splat_buffer.len;2067 len += 1;
2041 len += 1;2068 }
2042 }2069 if (remaining_splat > 0 and len < iovecs.len) {
2043 if (remaining_splat > 0 and len < iovecs.len) {2070 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
2044 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };2071 len += 1;
2045 len += 1;2072 }
2073 msg.iovlen = len;
2046 }2074 }
2047 msg.iovlen = len;2075 },
2048 }2076 }
2049 },2077 const flags = posix.MSG.NOSIGNAL;
2078 return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| {
2079 w.err = err;
2080 return error.WriteFailed;
2081 };
2050 }2082 }
2051 const flags = posix.MSG.NOSIGNAL;2083 },
2052 return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| {
2053 impl.err = err;
2054 return error.WriteFailed;
2055 };
2056 }
2057
2058 fn windows_writeFile(
2059 context: *anyopaque,
2060 in_file: std.fs.File,
2061 in_offset: u64,
2062 in_len: std.io.Writer.FileLen,
2063 headers_and_trailers: []const []const u8,
2064 headers_len: usize,
2065 ) std.io.Writer.FileError!usize {
2066 const len_int = switch (in_len) {
2067 .zero => return windows_writeSplat(context, headers_and_trailers, 1),
2068 .entire_file => std.math.maxInt(usize),
2069 else => in_len.int(),
2070 };
2071 if (headers_len > 0) return windows_writeSplat(context, headers_and_trailers[0..headers_len], 1);
2072 var file_contents_buffer: [4096]u8 = undefined;
2073 const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)];
2074 const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset);
2075 return windows_writeSplat(context, &.{read_buffer[0..n]}, 1);
2076 }
2077 };2084 };
20782085
2079 pub fn reader(stream: Stream) Reader {2086 pub fn reader(stream: Stream) Reader {
2080 return switch (native_os) {2087 return switch (native_os) {
2081 .windows => .{ .impl = stream },2088 .windows => .{ .stream = stream },
2082 else => .{ .impl = .{2089 else => .{ .file_reader = .{
2083 .fr = .{2090 .file = .{ .handle = stream.handle },
2084 .file = .{ .handle = stream.handle },2091 .mode = .streaming,
2085 .mode = .streaming,2092 .seek_err = error.Unseekable,
2086 .seek_err = error.Unseekable,
2087 },
2088 .err = {},
2089 } },2093 } },
2090 };2094 };
2091 }2095 }
20922096
2093 pub fn writer(stream: Stream) Writer {2097 pub fn writer(stream: Stream) Writer {
2094 return switch (native_os) {2098 return switch (native_os) {
2095 .windows => .{ .impl = stream },2099 .windows => .{ .stream = stream },
2096 else => .{ .impl = .{2100 else => .{ .file_writer = .{
2097 .fw = .{2101 .file = .{ .handle = stream.handle },
2098 .file = .{ .handle = stream.handle },2102 .mode = .streaming,
2099 .mode = .streaming,
2100 },
2101 .err = {},
2102 } },2103 } },
2103 };2104 };
2104 }2105 }