authorgravatar for quae@daurnimator.comdaurnimator <quae@daurnimator.com> 2021-08-23 05:22:53+10:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-08-22 22:22:53+03:00
log72c4b80d31c3ccecbd8cf96e5afdf756e055dc6a
tree08db5921f6b3c08fb9f6590fac8c29f9941c4c25
parent62e3d67605075f27134736917495e7a7a17869f6
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std.os: (p)writev should perform partial writes if iov.len > IOV_MAX

Co-authored-by: Veikka Tuominen <git@vexu.eu>

7 files changed, 26 insertions(+), 4 deletions(-)

lib/std/os.zig+4-4
...@@ -787,7 +787,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -787,7 +787,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
787/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are787/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
788/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.788/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
789///789///
790/// If `iov.len` is larger than will fit in a `u31`, a partial write will occur.790/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.
791pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {791pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
792 if (std.Target.current.os.tag == .windows) {792 if (std.Target.current.os.tag == .windows) {
793 // TODO improve this to use WriteFileScatter793 // TODO improve this to use WriteFileScatter
...@@ -816,7 +816,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {...@@ -816,7 +816,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
816 }816 }
817 }817 }
818818
819 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);819 const iov_count = if (iov.len > IOV_MAX) IOV_MAX else @intCast(u31, iov.len);
820 while (true) {820 while (true) {
821 const rc = system.writev(fd, iov.ptr, iov_count);821 const rc = system.writev(fd, iov.ptr, iov_count);
822 switch (errno(rc)) {822 switch (errno(rc)) {
...@@ -954,7 +954,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -954,7 +954,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
954/// * Darwin954/// * Darwin
955/// * Windows955/// * Windows
956///956///
957/// If `iov.len` is larger than will fit in a `u31`, a partial write will occur.957/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.
958pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usize {958pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usize {
959 const have_pwrite_but_not_pwritev = switch (std.Target.current.os.tag) {959 const have_pwrite_but_not_pwritev = switch (std.Target.current.os.tag) {
960 .windows, .macos, .ios, .watchos, .tvos, .haiku => true,960 .windows, .macos, .ios, .watchos, .tvos, .haiku => true,
...@@ -997,7 +997,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -997,7 +997,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
997 else997 else
998 system.pwritev;998 system.pwritev;
999999
1000 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);1000 const iov_count = if (iov.len > IOV_MAX) IOV_MAX else @intCast(u31, iov.len);
1001 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned1001 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
1002 while (true) {1002 while (true) {
1003 const rc = pwritev_sym(fd, iov.ptr, iov_count, ioffset);1003 const rc = pwritev_sym(fd, iov.ptr, iov_count, ioffset);
lib/std/os/bits/darwin.zig+1
...@@ -235,6 +235,7 @@ pub const host_t = mach_port_t;...@@ -235,6 +235,7 @@ pub const host_t = mach_port_t;
235pub const CALENDAR_CLOCK = 1;235pub const CALENDAR_CLOCK = 1;
236236
237pub const PATH_MAX = 1024;237pub const PATH_MAX = 1024;
238pub const IOV_MAX = 16;
238239
239pub const STDIN_FILENO = 0;240pub const STDIN_FILENO = 0;
240pub const STDOUT_FILENO = 1;241pub const STDOUT_FILENO = 1;
lib/std/os/bits/dragonfly.zig+1
...@@ -168,6 +168,7 @@ pub const SA_NOCLDWAIT = 0x0020;...@@ -168,6 +168,7 @@ pub const SA_NOCLDWAIT = 0x0020;
168pub const SA_SIGINFO = 0x0040;168pub const SA_SIGINFO = 0x0040;
169169
170pub const PATH_MAX = 1024;170pub const PATH_MAX = 1024;
171pub const IOV_MAX = KERN_IOV_MAX;
171172
172pub const ino_t = c_ulong;173pub const ino_t = c_ulong;
173174
lib/std/os/bits/freebsd.zig+2
...@@ -238,8 +238,10 @@ pub const CTL_DEBUG = 5;...@@ -238,8 +238,10 @@ pub const CTL_DEBUG = 5;
238238
239pub const KERN_PROC = 14; // struct: process entries239pub const KERN_PROC = 14; // struct: process entries
240pub const KERN_PROC_PATHNAME = 12; // path to executable240pub const KERN_PROC_PATHNAME = 12; // path to executable
241pub const KERN_IOV_MAX = 35;
241242
242pub const PATH_MAX = 1024;243pub const PATH_MAX = 1024;
244pub const IOV_MAX = KERN_IOV_MAX;
243245
244pub const STDIN_FILENO = 0;246pub const STDIN_FILENO = 0;
245pub const STDOUT_FILENO = 1;247pub const STDOUT_FILENO = 1;
lib/std/os/bits/netbsd.zig+2
...@@ -405,8 +405,10 @@ pub const CTL_DEBUG = 5;...@@ -405,8 +405,10 @@ pub const CTL_DEBUG = 5;
405405
406pub const KERN_PROC_ARGS = 48; // struct: process argv/env406pub const KERN_PROC_ARGS = 48; // struct: process argv/env
407pub const KERN_PROC_PATHNAME = 5; // path to executable407pub const KERN_PROC_PATHNAME = 5; // path to executable
408pub const KERN_IOV_MAX = 38;
408409
409pub const PATH_MAX = 1024;410pub const PATH_MAX = 1024;
411pub const IOV_MAX = KERN_IOV_MAX;
410412
411pub const STDIN_FILENO = 0;413pub const STDIN_FILENO = 0;
412pub const STDOUT_FILENO = 1;414pub const STDOUT_FILENO = 1;
lib/std/os/bits/wasi.zig+2
...@@ -76,6 +76,8 @@ pub const kernel_stat = struct {...@@ -76,6 +76,8 @@ pub const kernel_stat = struct {
76 }76 }
77};77};
7878
79pub const IOV_MAX = 1024;
80
79pub const AT_REMOVEDIR: u32 = 0x4;81pub const AT_REMOVEDIR: u32 = 0x4;
80pub const AT_FDCWD: fd_t = -2;82pub const AT_FDCWD: fd_t = -2;
8183
lib/std/os/test.zig+14
...@@ -786,3 +786,17 @@ test "dup & dup2" {...@@ -786,3 +786,17 @@ test "dup & dup2" {
786 var buf: [7]u8 = undefined;786 var buf: [7]u8 = undefined;
787 try testing.expectEqualStrings("dupdup2", buf[0..try file.readAll(&buf)]);787 try testing.expectEqualStrings("dupdup2", buf[0..try file.readAll(&buf)]);
788}788}
789
790test "writev longer than IOV_MAX" {
791 if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
792
793 var tmp = tmpDir(.{});
794 defer tmp.cleanup();
795
796 var file = try tmp.dir.createFile("pwritev", .{});
797 defer file.close();
798
799 const iovecs = [_]os.iovec_const{.{ .iov_base = "a", .iov_len = 1 }} ** (os.IOV_MAX + 1);
800 const amt = try file.writev(&iovecs);
801 try testing.expectEqual(@as(usize, os.IOV_MAX), amt);
802}