aboutsummaryrefslogtreecommitdiff
path: root/lib/std/fs
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-03-16 04:11:41 -0400
committerGitHub <noreply@github.com>2023-03-16 04:11:41 -0400
commitbd242ce1ce9ef6ffb1af4432d892bf582dcdba8a (patch)
tree34caaa3f320e8830a5f1f1c93a4b5d70c0d192a8 /lib/std/fs
parenta2c6ecd6dc0bdbe2396be9b055852324f16d34c9 (diff)
parent7177b3994626114e57bf8df36ca84fd942bac282 (diff)
downloadzig-bd242ce1ce9ef6ffb1af4432d892bf582dcdba8a.tar.gz
zig-bd242ce1ce9ef6ffb1af4432d892bf582dcdba8a.zip
Merge pull request #14647 from ziglang/build-parallel
zig build: run steps in parallel
Diffstat (limited to 'lib/std/fs')
-rw-r--r--lib/std/fs/file.zig38
-rw-r--r--lib/std/fs/test.zig30
2 files changed, 55 insertions, 13 deletions
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index bf93a61239..8235b8aecf 100644
--- a/lib/std/fs/file.zig
+++ b/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) {
@@ -1181,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..]);
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index 16458d7dc4..1fbd7dbd63 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -1124,17 +1124,31 @@ test "open file with exclusive lock twice, make sure second lock waits" {
test "open file with exclusive nonblocking lock twice (absolute paths)" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
- const allocator = testing.allocator;
+ var random_bytes: [12]u8 = undefined;
+ std.crypto.random.bytes(&random_bytes);
- const cwd = try std.process.getCwdAlloc(allocator);
- defer allocator.free(cwd);
- const file_paths: [2][]const u8 = .{ cwd, "zig-test-absolute-paths.txt" };
- const filename = try fs.path.resolve(allocator, &file_paths);
- defer allocator.free(filename);
+ var random_b64: [fs.base64_encoder.calcSize(random_bytes.len)]u8 = undefined;
+ _ = fs.base64_encoder.encode(&random_b64, &random_bytes);
- const file1 = try fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true });
+ const sub_path = random_b64 ++ "-zig-test-absolute-paths.txt";
- const file2 = fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true });
+ const gpa = testing.allocator;
+
+ const cwd = try std.process.getCwdAlloc(gpa);
+ defer gpa.free(cwd);
+
+ const filename = try fs.path.resolve(gpa, &[_][]const u8{ cwd, sub_path });
+ defer gpa.free(filename);
+
+ const file1 = try fs.createFileAbsolute(filename, .{
+ .lock = .Exclusive,
+ .lock_nonblocking = true,
+ });
+
+ const file2 = fs.createFileAbsolute(filename, .{
+ .lock = .Exclusive,
+ .lock_nonblocking = true,
+ });
file1.close();
try testing.expectError(error.WouldBlock, file2);