diff options
| author | bors <bors@rust-lang.org> | 2022-06-10 11:50:39 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-06-10 11:50:39 +0000 |
| commit | ec55c61305eaf385fc1b93ac9a78284b4d887fe5 (patch) | |
| tree | 5b6abe8dc4a2278044d14457fb5f298b25e0527b /library/std/src/sys/unix/mod.rs | |
| parent | f19ccc2e8dab09e542d4c5a3ec14c7d5bce8d50e (diff) | |
| parent | 2e62fdab76bd92d0d381589fc85602efad93c846 (diff) | |
| download | rust-ec55c61305eaf385fc1b93ac9a78284b4d887fe5.tar.gz rust-ec55c61305eaf385fc1b93ac9a78284b4d887fe5.zip | |
Auto merge of #96837 - tmiasko:stdio-fcntl, r=joshtriplett
Use `fcntl(fd, F_GETFD)` to detect if standard streams are open In the previous implementation, if the standard streams were open, but the RLIMIT_NOFILE value was below three, the poll would fail with EINVAL: > ERRORS: EINVAL The nfds value exceeds the RLIMIT_NOFILE value. Switch to the existing fcntl based implementation to avoid the issue. Fixes #96621.
Diffstat (limited to 'library/std/src/sys/unix/mod.rs')
| -rw-r--r-- | library/std/src/sys/unix/mod.rs | 91 |
1 files changed, 56 insertions, 35 deletions
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 1505878e18c..ddec60961f0 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -77,35 +77,65 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } unsafe fn sanitize_standard_fds() { - #[cfg(not(miri))] - // The standard fds are always available in Miri. - cfg_if::cfg_if! { - if #[cfg(not(any( - target_os = "emscripten", - target_os = "fuchsia", - target_os = "vxworks", - // The poll on Darwin doesn't set POLLNVAL for closed fds. - target_os = "macos", - target_os = "ios", - target_os = "redox", - target_os = "l4re", - )))] { - use crate::sys::os::errno; - let pfds: &mut [_] = &mut [ - libc::pollfd { fd: 0, events: 0, revents: 0 }, - libc::pollfd { fd: 1, events: 0, revents: 0 }, - libc::pollfd { fd: 2, events: 0, revents: 0 }, - ]; - while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 { - if errno() == libc::EINTR { - continue; + // fast path with a single syscall for systems with poll() + #[cfg(not(any( + miri, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "vxworks", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_os = "macos", + target_os = "ios", + target_os = "redox", + target_os = "l4re", + )))] + 'poll: { + use crate::sys::os::errno; + let pfds: &mut [_] = &mut [ + libc::pollfd { fd: 0, events: 0, revents: 0 }, + libc::pollfd { fd: 1, events: 0, revents: 0 }, + libc::pollfd { fd: 2, events: 0, revents: 0 }, + ]; + + while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 { + match errno() { + libc::EINTR => continue, + libc::EINVAL | libc::EAGAIN | libc::ENOMEM => { + // RLIMIT_NOFILE or temporary allocation failures + // may be preventing use of poll(), fall back to fcntl + break 'poll; } + _ => libc::abort(), + } + } + for pfd in pfds { + if pfd.revents & libc::POLLNVAL == 0 { + continue; + } + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. libc::abort(); } - for pfd in pfds { - if pfd.revents & libc::POLLNVAL == 0 { - continue; - } + } + return; + } + + // fallback in case poll isn't available or limited by RLIMIT_NOFILE + #[cfg(not(any( + // The standard fds are always available in Miri. + miri, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "vxworks", + target_os = "l4re", + )))] + { + use crate::sys::os::errno; + for fd in 0..3 { + if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of @@ -114,15 +144,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { libc::abort(); } } - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] { - use crate::sys::os::errno; - for fd in 0..3 { - if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { - libc::abort(); - } - } - } } } } |
