authorgravatar for joran@ronomon.comJoran Dirk Greef <joran@ronomon.com> 2021-01-23 10:41:09+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-25 10:41:38-08:00
log881ecdc72ff1fc7dccc586c5d361e469db7c45d8
treed88034616734b0d203f6c466d44a74b330d3f548
parent09450419d3bfe990b4e34f85f673615ae601b0d3

Add MAX_RW_COUNT limit to std.os.pread()

Fixes: https://github.com/ziglang/zig/issues/7805

1 files changed, 17 insertions(+), 3 deletions(-)

lib/std/os.zig+17-3
......@@ -324,7 +324,7 @@ pub const ReadError = error{
324324/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
325325/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
326326/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
327/// For POSIX the limit is `math.maxInt(isize)`.
327/// The corresponding POSIX limit is `math.maxInt(isize)`.
328328pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
329329 if (builtin.os.tag == .windows) {
330330 return windows.ReadFile(fd, buf, null, std.io.default_mode);
......@@ -447,6 +447,12 @@ pub const PReadError = ReadError || error{Unseekable};
447447/// return error.WouldBlock when EAGAIN is received.
448448/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
449449/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
450///
451/// Linux has a limit on how many bytes may be transferred in one `pread` call, which is `0x7ffff000`
452/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
453/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
454/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
455/// The corresponding POSIX limit is `math.maxInt(isize)`.
450456pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
451457 if (builtin.os.tag == .windows) {
452458 return windows.ReadFile(fd, buf, offset, std.io.default_mode);
......@@ -478,8 +484,16 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
478484 }
479485 }
480486
487 // Prevent EINVAL.
488 const max_count = switch (std.Target.current.os.tag) {
489 .linux => 0x7ffff000,
490 .macos, .ios, .watchos, .tvos => math.maxInt(i32),
491 else => math.maxInt(isize),
492 };
493 const adjusted_len = math.min(max_count, buf.len);
494
481495 while (true) {
482 const rc = system.pread(fd, buf.ptr, buf.len, offset);
496 const rc = system.pread(fd, buf.ptr, adjusted_len, offset);
483497 switch (errno(rc)) {
484498 0 => return @intCast(usize, rc),
485499 EINTR => continue,
......@@ -4926,7 +4940,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize {
49264940///
49274941/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`
49284942/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
4929/// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page.
4943/// well as stuffing the errno codes into the last `4096` values. This is noted on the `sendfile` man page.
49304944/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
49314945/// The corresponding POSIX limit on this is `math.maxInt(isize)`.
49324946pub fn sendfile(