Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problematic ssize_t to int conversion in uv_fs_write #3360

Open
zbjornson opened this issue Nov 10, 2021 · 6 comments
Open

Problematic ssize_t to int conversion in uv_fs_write #3360

zbjornson opened this issue Nov 10, 2021 · 6 comments

Comments

@zbjornson
Copy link
Contributor

  • Version: 1.42.0
  • Platform: Linux/Unix (generic)

uv_fs_write returns an int, but the underlying Linux syscalls return a ssize_t. That conversion is problematic for large writes and has caused a few bugs in Node.js, including:

There are a handful of issues about related compiler warnings (#708, #2714), but I don't see an issue for the actual bug.

I think the only way to fix this without a breaking change is to add ssize_t uv_fs_write64 or ssize_t uv_fs_write2 or something. uv_fs_s's result property is already a ssize_t, so only the return type needs changing.

@vtjnash
Copy link
Member

vtjnash commented Nov 10, 2021

Somewhat fixed by #1501, but there was enough problems with it at the OS level, I changed my mind and think we are better off documenting the maximum size legal write (~2GB), and then expecting applications to handle that case themselves.

@bnoordhuis
Copy link
Member

#1501 stalled on ABI issues, IIRC? I can see two ways to attack this issue:

  1. limit reads and writes to ~2GB
  2. change uv_fs_write() et al to return ssize_t or int64_t

(1) means libuv users now have to handle partial writes (but the current behavior is broken too)

(2) is technically an API and ABI break, although I expect in practice it'll be fine

@vtjnash
Copy link
Member

vtjnash commented Nov 11, 2021

#1501 stalled for several reasons, the primary one being that most kernels also can't handle reads and writes over 2GB either. This doesn't make much difference to reads (since those are chunked explicitly anyways), but makes it hard to form the return value for the write calls (and is an API break to make these all return off_t / int64_t, though perhaps we want to do that for v2 regardless). My ending suggestion was to make libuv return UV_EINVAL for all writes larger than some documented maximum (empirically, about 2^31 - 4096 bytes for unix and 511 MB for windows, or 0x7ffff000 and 0x1ff00000 respectively), and force the application (e.g. nodejs or julia) to chunk it as needed.

@stale
Copy link

stale bot commented Jan 9, 2022

This issue has been automatically marked as stale because it has not had recent activity. Thank you for your contributions.

@stale stale bot added the stale label Jan 9, 2022
@trevnorris
Copy link
Member

@vtjnash I see in https://man7.org/linux/man-pages/man2/write.2.html#NOTES that write(2) has a transfer limit of 0x7ffff000. Does that pertain to any individual uv_buf_t (for when writev() is called), or the entire write_queue_size? And what about returning UV_EFBIG instead of UV_EINVAL to be more explicit?

@stale stale bot removed the stale label Mar 16, 2023
@vtjnash
Copy link
Member

vtjnash commented Mar 16, 2023

Each syscall (summed across all buffers in the vector)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants