Skip to content

Commit

Permalink
std.fs.File.readvAll: fix behavior for 0-length vectors
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
andrewrk committed Mar 15, 2023
1 parent 7db7400 commit 25c3878
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
21 changes: 18 additions & 3 deletions lib/std/fs/file.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions lib/std/os.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 25c3878

Please sign in to comment.