authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-09-13 09:42:00+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-13 16:31:21-04:00
log5e50d145d964238a68d4780e253d26431e7c7994
tree4f7cbc281a0efeb742372c36f8c2dd9f41a5f988
parent9fe4c89230df2d78c8bf37b4b1d7a9bedb92677b

std: Limit the read/write size on Darwin

It turns out that the kernel won't read or write more than 0x7fffffff bytes in a single call, failing with EINVAL when trying to do so. Adjust the limit and curse whoever is responsible for this. Closes #6332

1 files changed, 9 insertions(+), 1 deletions(-)

lib/std/os.zig+9-1
...@@ -320,6 +320,7 @@ pub const ReadError = error{...@@ -320,6 +320,7 @@ pub const ReadError = error{
320/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`320/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`
321/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as321/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
322/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.322/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
323/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
323/// For POSIX the limit is `math.maxInt(isize)`.324/// For POSIX the limit is `math.maxInt(isize)`.
324pub fn read(fd: fd_t, buf: []u8) ReadError!usize {325pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
325 if (builtin.os.tag == .windows) {326 if (builtin.os.tag == .windows) {
...@@ -353,6 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -353,6 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
353 // Prevents EINVAL.354 // Prevents EINVAL.
354 const max_count = switch (std.Target.current.os.tag) {355 const max_count = switch (std.Target.current.os.tag) {
355 .linux => 0x7ffff000,356 .linux => 0x7ffff000,
357 .macosx, .ios, .watchos, .tvos => math.maxInt(i32),
356 else => math.maxInt(isize),358 else => math.maxInt(isize),
357 };359 };
358 const adjusted_len = math.min(max_count, buf.len);360 const adjusted_len = math.min(max_count, buf.len);
...@@ -693,6 +695,7 @@ pub const WriteError = error{...@@ -693,6 +695,7 @@ pub const WriteError = error{
693/// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000`695/// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000`
694/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as696/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
695/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.697/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
698/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
696/// The corresponding POSIX limit is `math.maxInt(isize)`.699/// The corresponding POSIX limit is `math.maxInt(isize)`.
697pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {700pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
698 if (builtin.os.tag == .windows) {701 if (builtin.os.tag == .windows) {
...@@ -726,6 +729,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -726,6 +729,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
726729
727 const max_count = switch (std.Target.current.os.tag) {730 const max_count = switch (std.Target.current.os.tag) {
728 .linux => 0x7ffff000,731 .linux => 0x7ffff000,
732 .macosx, .ios, .watchos, .tvos => math.maxInt(i32),
729 else => math.maxInt(isize),733 else => math.maxInt(isize),
730 };734 };
731 const adjusted_len = math.min(max_count, bytes.len);735 const adjusted_len = math.min(max_count, bytes.len);
...@@ -851,6 +855,7 @@ pub const PWriteError = WriteError || error{Unseekable};...@@ -851,6 +855,7 @@ pub const PWriteError = WriteError || error{Unseekable};
851/// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000`855/// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000`
852/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as856/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
853/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.857/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
858/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
854/// The corresponding POSIX limit is `math.maxInt(isize)`.859/// The corresponding POSIX limit is `math.maxInt(isize)`.
855pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {860pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
856 if (std.Target.current.os.tag == .windows) {861 if (std.Target.current.os.tag == .windows) {
...@@ -888,6 +893,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -888,6 +893,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
888 // Prevent EINVAL.893 // Prevent EINVAL.
889 const max_count = switch (std.Target.current.os.tag) {894 const max_count = switch (std.Target.current.os.tag) {
890 .linux => 0x7ffff000,895 .linux => 0x7ffff000,
896 .macosx, .ios, .watchos, .tvos => math.maxInt(i32),
891 else => math.maxInt(isize),897 else => math.maxInt(isize),
892 };898 };
893 const adjusted_len = math.min(max_count, bytes.len);899 const adjusted_len = math.min(max_count, bytes.len);
...@@ -3084,7 +3090,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con...@@ -3084,7 +3090,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
3084 .WSAECONNREFUSED => return error.ConnectionRefused,3090 .WSAECONNREFUSED => return error.ConnectionRefused,
3085 .WSAETIMEDOUT => return error.ConnectionTimedOut,3091 .WSAETIMEDOUT => return error.ConnectionTimedOut,
3086 .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well?3092 .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well?
3087 , .WSAENETUNREACH => return error.NetworkUnreachable,3093 , .WSAENETUNREACH => return error.NetworkUnreachable,
3088 .WSAEFAULT => unreachable,3094 .WSAEFAULT => unreachable,
3089 .WSAEINVAL => unreachable,3095 .WSAEINVAL => unreachable,
3090 .WSAEISCONN => unreachable,3096 .WSAEISCONN => unreachable,
...@@ -4711,6 +4717,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize {...@@ -4711,6 +4717,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize {
4711/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`4717/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`
4712/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as4718/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
4713/// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page.4719/// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page.
4720/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
4714/// The corresponding POSIX limit on this is `math.maxInt(isize)`.4721/// The corresponding POSIX limit on this is `math.maxInt(isize)`.
4715pub fn sendfile(4722pub fn sendfile(
4716 out_fd: fd_t,4723 out_fd: fd_t,
...@@ -4733,6 +4740,7 @@ pub fn sendfile(...@@ -4733,6 +4740,7 @@ pub fn sendfile(
4733 });4740 });
4734 const max_count = switch (std.Target.current.os.tag) {4741 const max_count = switch (std.Target.current.os.tag) {
4735 .linux => 0x7ffff000,4742 .linux => 0x7ffff000,
4743 .macosx, .ios, .watchos, .tvos => math.maxInt(i32),
4736 else => math.maxInt(size_t),4744 else => math.maxInt(size_t),
4737 };4745 };
47384746