fixup! io: make libuv 64-bit safe

This commit is contained in:
Jameson Nash 2026-03-18 23:56:53 +00:00
parent 533a669ac6
commit 58edef0ca9
9 changed files with 45 additions and 45 deletions

View File

@ -520,33 +520,35 @@ static int uv__fs_read(uv_fs_t* req) {
if (nbufs > iovmax)
nbufs = iovmax;
/* Truncate multi-buf reads to IO_MAX_BYTES total, dropping trailing bufs. */
/* Truncate multi-buf reads to UV__IO_MAX_BYTES total, dropping trailing bufs. */
if (nbufs > 1) {
size_t total;
size_t n;
for (total = 0, n = 0; n < nbufs; n++) {
if (bufs[n].iov_len > IO_MAX_BYTES - total)
if (bufs[n].iov_len > UV__IO_MAX_BYTES - total)
break;
total += bufs[n].iov_len;
}
if (n < nbufs)
nbufs = n > 0 ? n : 1;
nbufs = n > 0 ? n : 1;
}
r = 0;
if (off < 0) {
if (nbufs == 1)
if (nbufs == 1) {
r = read(fd, bufs->iov_base,
bufs->iov_len > IO_MAX_BYTES ? IO_MAX_BYTES : bufs->iov_len);
else if (nbufs > 1)
bufs->iov_len > UV__IO_MAX_BYTES ? UV__IO_MAX_BYTES : bufs->iov_len);
} else if (nbufs > 1) {
r = readv(fd, bufs, nbufs);
}
} else {
if (nbufs == 1)
if (nbufs == 1) {
r = pread(fd, bufs->iov_base,
bufs->iov_len > IO_MAX_BYTES ? IO_MAX_BYTES : bufs->iov_len,
bufs->iov_len > UV__IO_MAX_BYTES ? UV__IO_MAX_BYTES : bufs->iov_len,
off);
else if (nbufs > 1)
}
else if (nbufs > 1) {
r = uv__preadv(fd, bufs, nbufs, off);
}
}
#ifdef __PASE__
@ -2166,7 +2168,7 @@ int uv_fs_sendfile(uv_loop_t* loop,
req->flags = in_fd; /* hack */
req->file = out_fd;
req->off = off;
if (len > IO_MAX_BYTES)
if (len > UV__IO_MAX_BYTES)
return UV_EINVAL;
req->bufsml[0].len = len;
POST;
@ -2235,7 +2237,7 @@ int uv_fs_write(uv_loop_t* loop,
if (bufs == NULL || nbufs == 0)
return UV_EINVAL;
if (uv__count_bufs(bufs, nbufs) > IO_MAX_BYTES)
if (uv__count_bufs(bufs, nbufs) > UV__IO_MAX_BYTES)
return UV_EINVAL;
req->file = file;

View File

@ -78,7 +78,6 @@ static size_t uv__write_req_size(uv_write_t* req);
static void uv__drain(uv_stream_t* stream);
void uv__stream_init(uv_loop_t* loop,
uv_stream_t* stream,
uv_handle_type type) {
@ -1058,15 +1057,15 @@ static void uv__read(uv_stream_t* stream) {
assert(uv__stream_fd(stream) >= 0);
if (!is_ipc) {
do
do {
nread = read(uv__stream_fd(stream),
buf.base,
buf.len > IO_MAX_BYTES ? IO_MAX_BYTES : buf.len);
while (nread < 0 && errno == EINTR);
buf.len > UV__IO_MAX_BYTES ? UV__IO_MAX_BYTES : buf.len);
} while (nread < 0 && errno == EINTR);
} else {
/* ipc uses recvmsg */
if (buf.len > IO_MAX_BYTES)
buf.len = IO_MAX_BYTES;
if (buf.len > UV__IO_MAX_BYTES)
buf.len = UV__IO_MAX_BYTES;
msg.msg_flags = 0;
msg.msg_iov = (struct iovec*) &buf;
msg.msg_iovlen = 1;
@ -1078,8 +1077,7 @@ static void uv__read(uv_stream_t* stream) {
do {
nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
}
while (nread < 0 && errno == EINTR);
} while (nread < 0 && errno == EINTR);
}
if (nread < 0) {
@ -1314,11 +1312,11 @@ static int uv__check_before_write(uv_stream_t* stream,
if (nbufs < 1 || nbufs > 1024*1024)
return UV_EINVAL;
/* Reject writes above IO_MAX_BYTES to be consistent with EINVAL on platforms
/* Reject writes above UV__IO_MAX_BYTES to be consistent with EINVAL on platforms
* such as macOS that fail when the total size of the iov exceeds 2GB,
* and catch/prevent sign-extension bugs.
*/
if (uv__count_bufs(bufs, nbufs) > IO_MAX_BYTES)
if (uv__count_bufs(bufs, nbufs) > UV__IO_MAX_BYTES)
return UV_EINVAL;
if (uv__stream_fd(stream) < 0)

View File

@ -486,7 +486,7 @@ int uv__udp_check_before_send(uv_udp_t* handle,
if (nbufs < 1 || nbufs > 1024 * 1024)
return UV_EINVAL;
if (uv__count_bufs(bufs, nbufs) > IO_MAX_BYTES)
if (uv__count_bufs(bufs, nbufs) > UV__IO_MAX_BYTES)
return UV_EINVAL;
return addrlen;

View File

@ -230,7 +230,7 @@ size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
* an EINVAL. On Linux, IO syscalls will transfer at most this many bytes.
* Use this limit everywhere to avoid platform-specific failures.
*/
#define IO_MAX_BYTES 0x7ffff000
#define UV__IO_MAX_BYTES 0x7ffff000
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);

View File

@ -898,8 +898,8 @@ void fs__read(uv_fs_t* req) {
}
to_read = req->fs.info.bufs[index].len;
if (to_read > IO_MAX_BYTES)
to_read = IO_MAX_BYTES;
if (to_read > UV__IO_MAX_BYTES)
to_read = UV__IO_MAX_BYTES;
result = ReadFile(handle,
req->fs.info.bufs[index].base,
to_read,
@ -3333,7 +3333,7 @@ int uv_fs_write(uv_loop_t* loop,
return UV_EINVAL;
}
if (uv__count_bufs(bufs, nbufs) > IO_MAX_BYTES) {
if (uv__count_bufs(bufs, nbufs) > UV__IO_MAX_BYTES) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
@ -3707,7 +3707,7 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
req->file.fd = fd_in;
req->fs.info.fd_out = fd_out;
req->fs.info.offset = in_offset;
if (length > IO_MAX_BYTES)
if (length > UV__IO_MAX_BYTES)
return UV_EINVAL;
req->fs.info.bufsml[0].len = length;
POST;

View File

@ -1622,7 +1622,7 @@ static int uv__pipe_write_data(uv_loop_t* loop,
return err;
}
if (write_buf.len > IO_MAX_BYTES)
if (write_buf.len > UV__IO_MAX_BYTES)
return ERROR_INVALID_PARAMETER; /* Maps to UV_EINVAL. */
if ((handle->flags &
@ -1972,10 +1972,10 @@ static int uv__pipe_read_data(uv_loop_t* loop,
* (a) the length of the user-allocated buffer.
* (b) the maximum data length as specified by the `max_bytes` argument.
* (c) the amount of data that can be read non-blocking.
* (d) IO_MAX_BYTES.
* (d) UV__IO_MAX_BYTES.
*/
if (buf.len > IO_MAX_BYTES)
buf.len = IO_MAX_BYTES;
if (buf.len > UV__IO_MAX_BYTES)
buf.len = UV__IO_MAX_BYTES;
if (max_bytes > buf.len)
max_bytes = buf.len;

View File

@ -122,7 +122,7 @@ static int uv__check_before_write(uv_stream_t* handle,
return UV_EINVAL;
}
if (uv__count_bufs(bufs, nbufs) > IO_MAX_BYTES) {
if (uv__count_bufs(bufs, nbufs) > UV__IO_MAX_BYTES) {
return UV_EINVAL;
}

View File

@ -1103,8 +1103,8 @@ void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
break;
}
assert(buf.base != NULL);
if (buf.len > IO_MAX_BYTES)
buf.len = IO_MAX_BYTES;
if (buf.len > UV__IO_MAX_BYTES)
buf.len = UV__IO_MAX_BYTES;
flags = 0;
if (WSARecv(handle->socket,

View File

@ -20,7 +20,7 @@
*/
/* Verify that passing INT32_MAX as a buffer length is rejected with UV_EINVAL
* at the various I/O entry points that enforce IO_MAX_BYTES.
* at the various I/O entry points that enforce UV__IO_MAX_BYTES.
*/
#include "uv.h"
@ -59,17 +59,17 @@ TEST_IMPL(io_64_safe) {
loop = uv_default_loop();
/* A buf whose length just exceeds IO_MAX_BYTES (0x7ffff000). */
/* A buf whose length just exceeds UV__IO_MAX_BYTES (0x7ffff000). */
buf = uv_buf_init(NULL, INT32_MAX);
/* Two buffers whose individual sizes are reasonable but whose sum exceeds
* IO_MAX_BYTES (0x7ffff000). Each is 1 GiB + 1 byte.
* UV__IO_MAX_BYTES (0x7ffff000). Each is 1 GiB + 1 byte.
*/
bufs2[0] = uv_buf_init(NULL, 0x40000001u);
bufs2[1] = uv_buf_init(NULL, 0x40000001u);
/* ------------------------------------------------------------------ */
/* uv_fs_write: reject synchronous filesystem write > IO_MAX_BYTES. */
/* uv_fs_write: reject synchronous filesystem write > UV__IO_MAX_BYTES. */
/* ------------------------------------------------------------------ */
{
fd = uv_fs_open(NULL, &open_req, TEST_FILE,
@ -80,7 +80,7 @@ TEST_IMPL(io_64_safe) {
ASSERT_EQ(UV_EINVAL, uv_fs_write(NULL, &fs_req, fd, &buf, 1, 0, NULL));
uv_fs_req_cleanup(&fs_req);
/* nbufs > 1 where sum > IO_MAX_BYTES */
/* nbufs > 1 where sum > UV__IO_MAX_BYTES */
ASSERT_EQ(UV_EINVAL, uv_fs_write(NULL, &fs_req, fd, bufs2, 2, 0, NULL));
uv_fs_req_cleanup(&fs_req);
@ -89,7 +89,7 @@ TEST_IMPL(io_64_safe) {
}
/* ------------------------------------------------------------------ */
/* uv_fs_sendfile: reject len > IO_MAX_BYTES. */
/* uv_fs_sendfile: reject len > UV__IO_MAX_BYTES. */
/* ------------------------------------------------------------------ */
{
in_fd = uv_fs_open(NULL, &open_req, TEST_FILE,
@ -118,12 +118,12 @@ TEST_IMPL(io_64_safe) {
uv_fs_req_cleanup(&fs_req);
{
/* uv_write: reject stream write > IO_MAX_BYTES before queuing. */
/* uv_write: reject stream write > UV__IO_MAX_BYTES before queuing. */
ASSERT_OK(uv_tcp_init(loop, &tcp));
ASSERT_EQ(UV_EINVAL,
uv_write(&write_req, (uv_stream_t*) &tcp, &buf, 1, NULL));
/* nbufs > 1 where sum > IO_MAX_BYTES */
/* nbufs > 1 where sum > UV__IO_MAX_BYTES */
ASSERT_EQ(UV_EINVAL,
uv_write(&write_req, (uv_stream_t*) &tcp, bufs2, 2, NULL));
@ -140,7 +140,7 @@ TEST_IMPL(io_64_safe) {
ASSERT_OK(uv_udp_init(loop, &udp));
ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
/* uv_udp_try_send: reject UDP send > IO_MAX_BYTES. */
/* uv_udp_try_send: reject UDP send > UV__IO_MAX_BYTES. */
ASSERT_EQ(UV_EINVAL,
uv_udp_try_send(&udp, &buf, 1,
(const struct sockaddr*) &addr));
@ -160,7 +160,7 @@ TEST_IMPL(io_64_safe) {
uv_udp_send(&send_req, &udp, bufs2, 2,
(const struct sockaddr*) &addr, on_udp_send));
/* uv_udp_try_send2: reject per-batch size > IO_MAX_BYTES. */
/* uv_udp_try_send2: reject per-batch size > UV__IO_MAX_BYTES. */
t2_bufs[0] = &buf;
t2_nbufs[0] = 1;
t2_addrs[0] = (struct sockaddr*) &addr;