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{...@@ -324,7 +324,7 @@ pub const ReadError = error{
324/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as324/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
325/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.325/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
326/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.326/// 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)`.
328pub fn read(fd: fd_t, buf: []u8) ReadError!usize {328pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
329 if (builtin.os.tag == .windows) {329 if (builtin.os.tag == .windows) {
330 return windows.ReadFile(fd, buf, null, std.io.default_mode);330 return windows.ReadFile(fd, buf, null, std.io.default_mode);
...@@ -447,6 +447,12 @@ pub const PReadError = ReadError || error{Unseekable};...@@ -447,6 +447,12 @@ pub const PReadError = ReadError || error{Unseekable};
447/// return error.WouldBlock when EAGAIN is received.447/// return error.WouldBlock when EAGAIN is received.
448/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are448/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
449/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.449/// 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)`.
450pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {456pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
451 if (builtin.os.tag == .windows) {457 if (builtin.os.tag == .windows) {
452 return windows.ReadFile(fd, buf, offset, std.io.default_mode);458 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 {...@@ -478,8 +484,16 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
478 }484 }
479 }485 }
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
481 while (true) {495 while (true) {
482 const rc = system.pread(fd, buf.ptr, buf.len, offset);496 const rc = system.pread(fd, buf.ptr, adjusted_len, offset);
483 switch (errno(rc)) {497 switch (errno(rc)) {
484 0 => return @intCast(usize, rc),498 0 => return @intCast(usize, rc),
485 EINTR => continue,499 EINTR => continue,
...@@ -4926,7 +4940,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize {...@@ -4926,7 +4940,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize {
4926///4940///
4927/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`4941/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`
4928/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as4942/// 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.
4930/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.4944/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
4931/// The corresponding POSIX limit on this is `math.maxInt(isize)`.4945/// The corresponding POSIX limit on this is `math.maxInt(isize)`.
4932pub fn sendfile(4946pub fn sendfile(