authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-09 18:06:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:14-07:00
log25c3878c00b92ffc884d89d32817ca9c244f7972
treefa75c028981da826805ce1db00c21cfa671a36e7
parent7db74009db4a4dc820e3e32c805ab7e29394205b

std.fs.File.readvAll: 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.

2 files changed, 21 insertions(+), 3 deletions(-)

lib/std/fs/file.zig+18-3
......@@ -1048,12 +1048,27 @@ pub const File = struct {
10481048 /// Returns the number of bytes read. If the number read is smaller than the total bytes
10491049 /// from all the buffers, it means the file reached the end. Reaching the end of a file
10501050 /// is not an error condition.
1051 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
1052 /// order to handle partial reads from the underlying OS layer.
1053 /// See https://github.com/ziglang/zig/issues/7699
1051 ///
1052 /// The `iovecs` parameter is mutable because:
1053 /// * This function needs to mutate the fields in order to handle partial
1054 /// reads from the underlying OS layer.
1055 /// * The OS layer expects pointer addresses to be inside the application's address space
1056 /// even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer
1057 /// addresses when the length is zero. So this function modifies the iov_base fields
1058 /// when the length is zero.
1059 ///
1060 /// Related open issue: https://github.com/ziglang/zig/issues/7699
10541061 pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
10551062 if (iovecs.len == 0) return 0;
10561063
1064 // We use the address of this local variable for all zero-length
1065 // vectors so that the OS does not complain that we are giving it
1066 // addresses outside the application's address space.
1067 var garbage: [1]u8 = undefined;
1068 for (iovecs) |*v| {
1069 if (v.iov_len == 0) v.iov_base = &garbage;
1070 }
1071
10571072 var i: usize = 0;
10581073 var off: usize = 0;
10591074 while (true) {
lib/std/os.zig+3
......@@ -766,6 +766,9 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
766766/// This operation is non-atomic on the following systems:
767767/// * Windows
768768/// On these systems, the read races with concurrent writes to the same file descriptor.
769///
770/// This function assumes that all zero-length vectors have a pointer within the address
771/// space of the application.
769772pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
770773 if (builtin.os.tag == .windows) {
771774 // TODO improve this to use ReadFileScatter