Commit e098b287e1
lib/std/fs/file.zig
@@ -1196,13 +1196,26 @@ pub const File = struct {
}
}
- /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
- /// order to handle partial writes from the underlying OS layer.
+ /// The `iovecs` parameter is mutable because:
+ /// * This function needs to mutate the fields in order to handle partial
+ /// writes from the underlying OS layer.
+ /// * 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 modifies the iov_base fields
+ /// when the length is zero.
/// See https://github.com/ziglang/zig/issues/7699
/// See equivalent function: `std.net.Stream.writevAll`.
pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
if (iovecs.len == 0) return;
+ // We use the address of this local variable for all zero-length
+ // vectors so that the OS does not complain that we are giving it
+ // addresses outside the application's address space.
+ var garbage: [1]u8 = undefined;
+ for (iovecs) |*v| {
+ if (v.iov_len == 0) v.iov_base = &garbage;
+ }
+
var i: usize = 0;
while (true) {
var amt = try self.writev(iovecs[i..]);
lib/std/os.zig
@@ -767,8 +767,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
/// * Windows
/// On these systems, the read races with concurrent writes to the same file descriptor.
///
-/// This function assumes that all zero-length vectors have a pointer within the address
-/// space of the application.
+/// This function assumes that all vectors, including zero-length vectors, have
+/// a pointer within the address space of the application.
pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
if (builtin.os.tag == .windows) {
// TODO improve this to use ReadFileScatter
@@ -1170,6 +1170,9 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
///
/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.
+///
+/// This function assumes that all vectors, including zero-length vectors, have
+/// a pointer within the address space of the application.
pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
if (builtin.os.tag == .windows) {
// TODO improve this to use WriteFileScatter