authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-13 18:23:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:15-07:00
loge098b287e18b8a7a4df0fdb48d32fb4376daba07
treeae36d182b8fd3e3b8ee06dad0558fa3c08c4a52f
parentb1299d515351acbfa1f169c8e65a3fa2b3e39f1a

std.fs.File.writevAll: fix behavior for 0-length vectors

The OS layer expects pointer addresses to be inside the application's address space even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer addresses when the length is zero. So this function now modifies the iov_base fields when the length is zero. This is a companion commit to b4893eb05565b2cb033c6ed88617d73faf878455.

2 files changed, 20 insertions(+), 4 deletions(-)

lib/std/fs/file.zig+15-2
...@@ -1196,13 +1196,26 @@ pub const File = struct {...@@ -1196,13 +1196,26 @@ pub const File = struct {
1196 }1196 }
1197 }1197 }
11981198
1199 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in1199 /// The `iovecs` parameter is mutable because:
1200 /// order to handle partial writes from the underlying OS layer.1200 /// * This function needs to mutate the fields in order to handle partial
1201 /// writes from the underlying OS layer.
1202 /// * The OS layer expects pointer addresses to be inside the application's address space
1203 /// even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer
1204 /// addresses when the length is zero. So this function modifies the iov_base fields
1205 /// when the length is zero.
1201 /// See https://github.com/ziglang/zig/issues/76991206 /// See https://github.com/ziglang/zig/issues/7699
1202 /// See equivalent function: `std.net.Stream.writevAll`.1207 /// See equivalent function: `std.net.Stream.writevAll`.
1203 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {1208 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
1204 if (iovecs.len == 0) return;1209 if (iovecs.len == 0) return;
12051210
1211 // We use the address of this local variable for all zero-length
1212 // vectors so that the OS does not complain that we are giving it
1213 // addresses outside the application's address space.
1214 var garbage: [1]u8 = undefined;
1215 for (iovecs) |*v| {
1216 if (v.iov_len == 0) v.iov_base = &garbage;
1217 }
1218
1206 var i: usize = 0;1219 var i: usize = 0;
1207 while (true) {1220 while (true) {
1208 var amt = try self.writev(iovecs[i..]);1221 var amt = try self.writev(iovecs[i..]);
lib/std/os.zig+5-2
...@@ -767,8 +767,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -767,8 +767,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
767/// * Windows767/// * Windows
768/// On these systems, the read races with concurrent writes to the same file descriptor.768/// On these systems, the read races with concurrent writes to the same file descriptor.
769///769///
770/// This function assumes that all zero-length vectors have a pointer within the address770/// This function assumes that all vectors, including zero-length vectors, have
771/// space of the application.771/// a pointer within the address space of the application.
772pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {772pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
773 if (builtin.os.tag == .windows) {773 if (builtin.os.tag == .windows) {
774 // TODO improve this to use ReadFileScatter774 // TODO improve this to use ReadFileScatter
...@@ -1170,6 +1170,9 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -1170,6 +1170,9 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
1170/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.1170/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
1171///1171///
1172/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.1172/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.
1173///
1174/// This function assumes that all vectors, including zero-length vectors, have
1175/// a pointer within the address space of the application.
1173pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {1176pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
1174 if (builtin.os.tag == .windows) {1177 if (builtin.os.tag == .windows) {
1175 // TODO improve this to use WriteFileScatter1178 // TODO improve this to use WriteFileScatter