Commit 25c3878c00
lib/std/fs/file.zig
@@ -1048,12 +1048,27 @@ pub const File = struct {
/// Returns the number of bytes read. If the number read is smaller than the total bytes
/// from all the buffers, it means the file reached the end. Reaching the end of a file
/// is not an error condition.
- /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
- /// order to handle partial reads from the underlying OS layer.
- /// See https://github.com/ziglang/zig/issues/7699
+ ///
+ /// The `iovecs` parameter is mutable because:
+ /// * This function needs to mutate the fields in order to handle partial
+ /// reads 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.
+ ///
+ /// Related open issue: https://github.com/ziglang/zig/issues/7699
pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
if (iovecs.len == 0) return 0;
+ // 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;
var off: usize = 0;
while (true) {
lib/std/os.zig
@@ -766,6 +766,9 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
/// This operation is non-atomic on the following systems:
/// * 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.
pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
if (builtin.os.tag == .windows) {
// TODO improve this to use ReadFileScatter