diff options
Diffstat (limited to 'library/std')
71 files changed, 487 insertions, 328 deletions
diff --git a/library/std/src/env.rs b/library/std/src/env.rs index d732a15117e..27f4daba44b 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -653,19 +653,28 @@ pub fn home_dir() -> Option<PathBuf> { /// may result in "insecure temporary file" security vulnerabilities. Consider /// using a crate that securely creates temporary files or directories. /// +/// Note that the returned value may be a symbolic link, not a directory. +/// /// # Platform-specific behavior /// /// On Unix, returns the value of the `TMPDIR` environment variable if it is -/// set, otherwise for non-Android it returns `/tmp`. On Android, since there -/// is no global temporary folder (it is usually allocated per-app), it returns -/// `/data/local/tmp`. +/// set, otherwise the value is OS-specific: +/// - On Android, there is no global temporary folder (it is usually allocated +/// per-app), it returns `/data/local/tmp`. +/// - On Darwin-based OSes (macOS, iOS, etc) it returns the directory provided +/// by `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)`, as recommended by [Apple's +/// security guidelines][appledoc]. +/// - On all other unix-based OSes, it returns `/tmp`. +/// /// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] / /// [`GetTempPath`][GetTempPath], which this function uses internally. +/// /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior /// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a /// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha +/// [appledoc]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 /// /// ```no_run /// use std::env; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 79dfb47d0c4..328185d1f2b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -550,11 +550,15 @@ impl OsString { OsStr::from_inner_mut(self.inner.leak()) } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Truncate the the `OsString` to the specified length. + /// + /// # Panics + /// Panics if `len` does not lie on a valid `OsStr` boundary + /// (as described in [`OsStr::slice_encoded_bytes`]). #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + #[unstable(feature = "os_string_truncate", issue = "133262")] + pub fn truncate(&mut self, len: usize) { + self.as_os_str().inner.check_public_boundary(len); self.inner.truncate(len); } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 555e8804eab..2d5d869630e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2804,8 +2804,9 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// See [`fs::remove_file`] and [`fs::remove_dir`]. /// -/// `remove_dir_all` will fail if `remove_dir` or `remove_file` fail on any constituent paths, including the root path. +/// `remove_dir_all` will fail if `remove_dir` or `remove_file` fail on any constituent paths, including the root `path`. /// As a result, the directory you are deleting must exist, meaning that this function is not idempotent. +/// Additionally, `remove_dir_all` will also fail if the `path` is not a directory. /// /// Consider ignoring the error if validating the removal is not required for your use case. /// @@ -3019,7 +3020,7 @@ impl DirBuilder { match path.parent() { Some(p) => self.create_dir_all(p)?, None => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Uncategorized, "failed to create whole tree", )); diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 52fe49985c6..17721090db5 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -41,7 +41,7 @@ impl Buffer { match Box::try_new_uninit_slice(capacity) { Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), Err(_) => { - Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) + Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) } } } diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index c41bae2aa4e..574eb83dc56 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -96,7 +96,7 @@ impl<W: Write> BufWriter<W> { pub(crate) fn try_new_buffer() -> io::Result<Vec<u8>> { Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { - io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") + io::const_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") }) } @@ -238,7 +238,7 @@ impl<W: ?Sized + Write> BufWriter<W> { match r { Ok(0) => { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::WriteZero, "failed to write the buffered data", )); diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index fbfdb4fa023..b2ffeb0f95d 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -304,7 +304,7 @@ where self.pos = n; Ok(self.pos) } - None => Err(io::const_io_error!( + None => Err(io::const_error!( ErrorKind::InvalidInput, "invalid seek to a negative or overflowing position", )), @@ -446,7 +446,7 @@ fn reserve_and_pad<A: Allocator>( buf_len: usize, ) -> io::Result<usize> { let pos: usize = (*pos_mut).try_into().map_err(|_| { - io::const_io_error!( + io::const_error!( ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length", ) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 5d7adcace52..03f38e220a5 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -76,31 +76,31 @@ impl fmt::Debug for Error { #[allow(dead_code)] impl Error { pub(crate) const INVALID_UTF8: Self = - const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); + const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); pub(crate) const READ_EXACT_EOF: Self = - const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); + const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); - pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_io_error!( + pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!( ErrorKind::NotFound, "The number of hardware threads is not known for the target platform" ); pub(crate) const UNSUPPORTED_PLATFORM: Self = - const_io_error!(ErrorKind::Unsupported, "operation not supported on this platform"); + const_error!(ErrorKind::Unsupported, "operation not supported on this platform"); pub(crate) const WRITE_ALL_EOF: Self = - const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"); + const_error!(ErrorKind::WriteZero, "failed to write whole buffer"); pub(crate) const ZERO_TIMEOUT: Self = - const_io_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); + const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); } #[stable(feature = "rust1", since = "1.0.0")] impl From<alloc::ffi::NulError> for Error { /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. fn from(_: alloc::ffi::NulError) -> Error { - const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") + const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") } } @@ -151,27 +151,38 @@ pub type RawOsError = sys::RawOsError; // (For the sake of being explicit: the alignment requirement here only matters // if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't // matter at all) +#[doc(hidden)] +#[unstable(feature = "io_const_error_internals", issue = "none")] #[repr(align(4))] #[derive(Debug)] -pub(crate) struct SimpleMessage { - kind: ErrorKind, - message: &'static str, -} - -impl SimpleMessage { - pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self { - Self { kind, message } - } +pub struct SimpleMessage { + pub kind: ErrorKind, + pub message: &'static str, } -/// Creates and returns an `io::Error` for a given `ErrorKind` and constant -/// message. This doesn't allocate. -pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) { - $crate::io::error::Error::from_static_message({ - const MESSAGE_DATA: $crate::io::error::SimpleMessage = - $crate::io::error::SimpleMessage::new($kind, $message); - &MESSAGE_DATA - }) +/// Creates a new I/O error from a known kind of error and a string literal. +/// +/// Contrary to [`Error::new`], this macro does not allocate and can be used in +/// `const` contexts. +/// +/// # Example +/// ``` +/// #![feature(io_const_error)] +/// use std::io::{const_error, Error, ErrorKind}; +/// +/// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works"); +/// +/// fn not_here() -> Result<(), Error> { +/// Err(FAIL) +/// } +/// ``` +#[rustc_macro_transparency = "semitransparent"] +#[unstable(feature = "io_const_error", issue = "133448")] +#[allow_internal_unstable(hint_must_use, io_const_error_internals)] +pub macro const_error($kind:expr, $message:expr $(,)?) { + $crate::hint::must_use($crate::io::Error::from_static_message( + const { &$crate::io::SimpleMessage { kind: $kind, message: $message } }, + )) } // As with `SimpleMessage`: `#[repr(align(4))]` here is just because @@ -592,13 +603,15 @@ impl Error { /// /// This function does not allocate. /// - /// You should not use this directly, and instead use the `const_io_error!` - /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`. + /// You should not use this directly, and instead use the `const_error!` + /// macro: `io::const_error!(ErrorKind::Something, "some_message")`. /// /// This function should maybe change to `from_static_message<const MSG: &'static /// str>(kind: ErrorKind)` in the future, when const generics allow that. #[inline] - pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error { + #[doc(hidden)] + #[unstable(feature = "io_const_error_internals", issue = "none")] + pub const fn from_static_message(msg: &'static SimpleMessage) -> Error { Self { repr: Repr::new_simple_message(msg) } } diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 00d04984a38..edac6563478 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -1,4 +1,4 @@ -use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_io_error}; +use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error}; use crate::assert_matches::assert_matches; use crate::mem::size_of; use crate::sys::decode_error_kind; @@ -60,7 +60,7 @@ fn test_downcasting() { #[test] fn test_const() { - const E: Error = const_io_error!(ErrorKind::NotFound, "hello"); + const E: Error = const_error!(ErrorKind::NotFound, "hello"); assert_eq!(E.kind(), ErrorKind::NotFound); assert_eq!(E.to_string(), "hello"); @@ -110,13 +110,13 @@ fn test_simple_message_packing() { }}; } - let not_static = const_io_error!(Uncategorized, "not a constant!"); + let not_static = const_error!(Uncategorized, "not a constant!"); check_simple_msg!(not_static, Uncategorized, "not a constant!"); - const CONST: Error = const_io_error!(NotFound, "definitely a constant!"); + const CONST: Error = const_error!(NotFound, "definitely a constant!"); check_simple_msg!(CONST, NotFound, "definitely a constant!"); - static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!"); + static STATIC: Error = const_error!(BrokenPipe, "a constant, sort of!"); check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!"); } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 21e70774954..4ffb0463006 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -301,12 +301,15 @@ mod tests; pub use core::io::{BorrowedBuf, BorrowedCursor}; use core::slice::memchr; -pub(crate) use error::const_io_error; - #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use self::buffered::WriterPanicked; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use self::error::RawOsError; +#[doc(hidden)] +#[unstable(feature = "io_const_error_internals", issue = "none")] +pub use self::error::SimpleMessage; +#[unstable(feature = "io_const_error", issue = "133448")] +pub use self::error::const_error; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; pub(crate) use self::stdio::attempt_print_to_stderr; diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 89e806c0891..47cbb9614af 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -225,12 +225,12 @@ fn take_eof() { impl Read for R { fn read(&mut self, _: &mut [u8]) -> io::Result<usize> { - Err(io::const_io_error!(io::ErrorKind::Other, "")) + Err(io::const_error!(io::ErrorKind::Other, "")) } } impl BufRead for R { fn fill_buf(&mut self) -> io::Result<&[u8]> { - Err(io::const_io_error!(io::ErrorKind::Other, "")) + Err(io::const_error!(io::ErrorKind::Other, "")) } fn consume(&mut self, _amt: usize) {} } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5b94f036248..cf99a618e55 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -174,9 +174,6 @@ //! //! - after-main use of thread-locals, which also affects additional features: //! - [`thread::current()`] -//! - [`thread::scope()`] -//! - [`sync::mpmc`] -//! - [`sync::mpsc`] //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms //! //! @@ -288,7 +285,6 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] -#![feature(const_float_methods)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -344,6 +340,7 @@ #![feature(fmt_internals)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] +#![feature(hint_must_use)] #![feature(ip)] #![feature(lazy_get)] #![feature(maybe_uninit_slice)] @@ -414,6 +411,7 @@ // Only for const-ness: // tidy-alphabetical-start #![feature(const_collections_with_hasher)] +#![feature(io_const_error)] #![feature(thread_local_internals)] // tidy-alphabetical-end // @@ -658,6 +656,8 @@ pub mod arch { pub use std_detect::is_aarch64_feature_detected; #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] pub use std_detect::is_arm_feature_detected; + #[unstable(feature = "is_loongarch_feature_detected", issue = "117425")] + pub use std_detect::is_loongarch_feature_detected; #[unstable(feature = "is_riscv_feature_detected", issue = "111192")] pub use std_detect::is_riscv_feature_detected; #[stable(feature = "simd_x86", since = "1.27.0")] diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index 3b19c743b1e..ddd3b68dd2d 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -84,6 +84,6 @@ where } } Err(last_err.unwrap_or_else(|| { - io::const_io_error!(ErrorKind::InvalidInput, "could not resolve to any addresses") + io::const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses") })) } diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 6df47d7b0e0..674c5fb7d6e 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -203,9 +203,7 @@ impl UdpSocket { pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> { match addr.to_socket_addrs()?.next() { Some(addr) => self.0.send_to(buf, &addr), - None => { - Err(io::const_io_error!(ErrorKind::InvalidInput, "no addresses to send data to")) - } + None => Err(io::const_error!(ErrorKind::InvalidInput, "no addresses to send data to")), } } diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 2d087c03b04..388b8a88a1a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -173,16 +173,17 @@ impl Drop for OwnedFd { #[inline] fn drop(&mut self) { unsafe { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // opened after we closed ours. - // However, this is usually justified, as some of the major Unices - // do make sure to always close the FD, even when `close()` is interrupted, - // and the scenario is rare to begin with. - // Helpful link to an epic discussion by POSIX workgroup: - // http://austingroupbugs.net/view.php?id=529 + // Note that errors are ignored when closing a file descriptor. According to POSIX 2024, + // we can and indeed should retry `close` on `EINTR` + // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html), + // but it is not clear yet how well widely-used implementations are conforming with this + // mandate since older versions of POSIX left the state of the FD after an `EINTR` + // unspecified. Ignoring errors is "fine" because some of the major Unices (in + // particular, Linux) do make sure to always close the FD, even when `close()` is + // interrupted, and the scenario is rare to begin with. If we retried on a + // not-POSIX-compliant implementation, the consequences could be really bad since we may + // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to + // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529 #[cfg(not(target_os = "hermit"))] { #[cfg(unix)] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 253e1503cf7..56789f235fd 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -30,14 +30,14 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s let bytes = path.as_os_str().as_bytes(); if bytes.contains(&0) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "paths must not contain interior null bytes", )); } if bytes.len() >= addr.sun_path.len() { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "path must be shorter than SUN_LEN", )); @@ -119,7 +119,7 @@ impl SocketAddr { // linux returns zero bytes of address len = SUN_PATH_OFFSET as libc::socklen_t; // i.e., zero-length address } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "file descriptor did not correspond to a Unix socket", )); @@ -273,7 +273,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { addr.sun_family = libc::AF_UNIX as libc::sa_family_t; if name.len() + 1 > addr.sun_path.len() { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "abstract socket name must be shorter than SUN_LEN", )); diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 9ec3e387e2b..42aada131da 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -261,7 +261,7 @@ impl FileExt for fs::File { a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED, a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE, _ => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "invalid parameter 'advice'", )); @@ -560,6 +560,5 @@ pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> } fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str() - .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) + f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 1fcfb6e73ad..272641ea6c7 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -101,7 +101,7 @@ impl OwnedSocket { #[cfg(target_vendor = "uwp")] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP")) + Err(io::const_error!(io::ErrorKind::Unsupported, "Unavailable on UWP")) } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index b0291e3aa19..33a3e4332f3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2504,6 +2504,7 @@ impl Path { /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// /// assert!(path.strip_prefix("test").is_err()); + /// assert!(path.strip_prefix("/te").is_err()); /// assert!(path.strip_prefix("/haha").is_err()); /// /// let prefix = PathBuf::from("/test/"); @@ -3580,7 +3581,7 @@ impl Error for StripPrefixError { pub fn absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { let path = path.as_ref(); if path.as_os_str().is_empty() { - Err(io::const_io_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",)) + Err(io::const_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",)) } else { sys::path::absolute(path) } diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index b231bd871b3..e4731280ffe 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -12,6 +12,9 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; +#[unstable(feature = "async_closure", issue = "62290")] +#[doc(no_inline)] +pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; // Re-exported functions #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 2c8ba411f30..a467237fef1 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -346,7 +346,8 @@ impl<T> Channel<T> { } // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), @@ -397,7 +398,8 @@ impl<T> Channel<T> { } // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), diff --git a/library/std/src/sync/mpmc/context.rs b/library/std/src/sync/mpmc/context.rs index 2371d32d4ea..51aa7e82e78 100644 --- a/library/std/src/sync/mpmc/context.rs +++ b/library/std/src/sync/mpmc/context.rs @@ -69,7 +69,7 @@ impl Context { inner: Arc::new(Inner { select: AtomicUsize::new(Selected::Waiting.into()), packet: AtomicPtr::new(ptr::null_mut()), - thread: thread::current(), + thread: thread::current_or_unnamed(), thread_id: current_thread_id(), }), } @@ -112,8 +112,11 @@ impl Context { /// Waits until an operation is selected and returns it. /// /// If the deadline is reached, `Selected::Aborted` will be selected. + /// + /// # Safety + /// This may only be called from the thread this `Context` belongs to. #[inline] - pub fn wait_until(&self, deadline: Option<Instant>) -> Selected { + pub unsafe fn wait_until(&self, deadline: Option<Instant>) -> Selected { loop { // Check whether an operation has been selected. let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); @@ -126,7 +129,8 @@ impl Context { let now = Instant::now(); if now < end { - thread::park_timeout(end - now); + // SAFETY: guaranteed by caller. + unsafe { self.inner.thread.park_timeout(end - now) }; } else { // The deadline has been reached. Try aborting select. return match self.try_select(Selected::Aborted) { @@ -135,7 +139,8 @@ impl Context { }; } } else { - thread::park(); + // SAFETY: guaranteed by caller. + unsafe { self.inner.thread.park() }; } } } diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 523e6d2f3bb..d88914f5291 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -444,7 +444,8 @@ impl<T> Channel<T> { } // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 446881291e6..577997c07a6 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -190,7 +190,8 @@ impl<T> Channel<T> { drop(inner); // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), @@ -257,7 +258,8 @@ impl<T> Channel<T> { drop(inner); // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 29cad4400f1..48d442921f7 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -511,12 +511,15 @@ fn test_downgrade_basic() { } #[test] +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See <https://github.com/rust-lang/rust/issues/121950> for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] fn test_downgrade_observe() { // Taken from the test `test_rwlock_downgrade` from: // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs const W: usize = 20; - const N: usize = 100; + const N: usize = if cfg!(miri) { 40 } else { 100 }; // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring // that the value they wrote has not changed after downgrading. diff --git a/library/std/src/sys/pal/common/small_c_string.rs b/library/std/src/sys/pal/common/small_c_string.rs index 3c96714b5c5..f54505a856e 100644 --- a/library/std/src/sys/pal/common/small_c_string.rs +++ b/library/std/src/sys/pal/common/small_c_string.rs @@ -11,7 +11,7 @@ const MAX_STACK_ALLOCATION: usize = 384; const MAX_STACK_ALLOCATION: usize = 32; const NUL_ERR: io::Error = - io::const_io_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte"); + io::const_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte"); #[inline] pub fn run_path_with_cstr<T>(path: &Path, f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> { diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index 17d15ed2e50..11862a07608 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -294,7 +294,7 @@ impl OpenOptions { (false, _, true) => Ok(O_WRONLY | O_APPEND), (true, _, true) => Ok(O_RDWR | O_APPEND), (false, false, false) => { - Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid access mode")) + Err(io::const_error!(ErrorKind::InvalidInput, "invalid access mode")) } } } @@ -304,18 +304,16 @@ impl OpenOptions { (true, false) => {} (false, false) => { if self.truncate || self.create || self.create_new { - return Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid creation mode", - )); + return Err( + io::const_error!(ErrorKind::InvalidInput, "invalid creation mode",), + ); } } (_, true) => { if self.truncate && !self.create_new { - return Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid creation mode", - )); + return Err( + io::const_error!(ErrorKind::InvalidInput, "invalid creation mode",), + ); } } } diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index b62afb40a61..f03fca60344 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -42,7 +42,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> { } pub fn unsupported_err() -> crate::io::Error { - crate::io::const_io_error!( + crate::io::const_error!( crate::io::ErrorKind::Unsupported, "operation not supported on HermitCore yet", ) diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index d9baa091a23..4e12374203e 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -87,7 +87,7 @@ impl Socket { loop { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); } let timeout = timeout - elapsed; @@ -114,7 +114,7 @@ impl Socket { // for POLLHUP rather than read readiness if pollfd.revents & netc::POLLHUP != 0 { let e = self.take_error()?.unwrap_or_else(|| { - io::const_io_error!( + io::const_error!( io::ErrorKind::Uncategorized, "no error set after POLLHUP", ) diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index 41f2c3e2123..2a0b8dcb4ed 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -41,7 +41,7 @@ impl Thread { unsafe { drop(Box::from_raw(p)); } - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Unable to create thread!")) + Err(io::const_error!(io::ErrorKind::Uncategorized, "Unable to create thread!")) } else { Ok(Thread { tid: tid }) }; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 586ccd18c2f..ce8a2fed4bc 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -48,7 +48,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> { } pub fn unsupported_err() -> crate::io::Error { - crate::io::const_io_error!(ErrorKind::Unsupported, "operation not supported on SGX yet") + crate::io::const_error!(ErrorKind::Unsupported, "operation not supported on SGX yet") } /// This function is used to implement various functions that doesn't exist, @@ -59,7 +59,7 @@ pub fn unsupported_err() -> crate::io::Error { pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> { static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false); if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) { - Err(crate::io::const_io_error!( + Err(crate::io::const_error!( ErrorKind::Uncategorized, "operation can't be trusted to have any effect on SGX", )) diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index 776a96ff3b7..04dd10ad806 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -303,7 +303,7 @@ fn cstr(path: &Path) -> io::Result<CString> { if !path.starts_with(br"\") { // Relative paths aren't supported - return Err(crate::io::const_io_error!( + return Err(crate::io::const_error!( crate::io::ErrorKind::Unsupported, "relative path is not supported on this platform", )); @@ -314,10 +314,7 @@ fn cstr(path: &Path) -> io::Result<CString> { let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat(); CString::from_vec_with_nul(wrapped_path).map_err(|_| { - crate::io::const_io_error!( - io::ErrorKind::InvalidInput, - "path provided contains a nul byte", - ) + crate::io::const_error!(io::ErrorKind::InvalidInput, "path provided contains a nul byte",) }) } @@ -512,7 +509,7 @@ impl fmt::Debug for File { pub fn unlink(p: &Path) -> io::Result<()> { if stat(p)?.file_type().is_dir() { - Err(io::const_io_error!(io::ErrorKind::IsADirectory, "is a directory")) + Err(io::const_error!(io::ErrorKind::IsADirectory, "is a directory")) } else { error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) .map_err(|e| e.as_io_error())?; @@ -542,7 +539,7 @@ pub fn rmdir(p: &Path) -> io::Result<()> { .map_err(|e| e.as_io_error())?; Ok(()) } else { - Err(io::const_io_error!(io::ErrorKind::NotADirectory, "not a directory")) + Err(io::const_error!(io::ErrorKind::NotADirectory, "not a directory")) } } @@ -570,7 +567,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { pub fn readlink(p: &Path) -> io::Result<PathBuf> { // This target doesn't support symlinks stat(p)?; - Err(io::const_io_error!(io::ErrorKind::InvalidInput, "not a symbolic link")) + Err(io::const_error!(io::ErrorKind::InvalidInput, "not a symbolic link")) } pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/pal/solid/net.rs index c0818ecd856..5f6436807e2 100644 --- a/library/std/src/sys/pal/solid/net.rs +++ b/library/std/src/sys/pal/solid/net.rs @@ -175,7 +175,7 @@ impl Socket { }; match n { - 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")), + 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), _ => { let can_write = writefds.num_fds != 0; if !can_write { diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs index d8afcb91f67..57c28aed3b2 100644 --- a/library/std/src/sys/pal/solid/os.rs +++ b/library/std/src/sys/pal/solid/os.rs @@ -204,7 +204,7 @@ pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { /// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this /// function just returns a generic error. fn cvt_env(t: c_int) -> io::Result<c_int> { - if t == -1 { Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } + if t == -1 { Err(io::const_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } } pub fn temp_dir() -> PathBuf { diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index abc8e69a285..47d9add72b5 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -13,7 +13,7 @@ use r_efi::efi::{self, Guid}; use r_efi::protocols::{device_path, device_path_to_text, shell}; use crate::ffi::{OsStr, OsString}; -use crate::io::{self, const_io_error}; +use crate::io::{self, const_error}; use crate::mem::{MaybeUninit, size_of}; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; @@ -30,7 +30,7 @@ type BootUninstallMultipleProtocolInterfaces = unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status; const BOOT_SERVICES_UNAVAILABLE: io::Error = - const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available"); + const_error!(io::ErrorKind::Other, "Boot Services are no longer available"); /// Locates Handles with a particular Protocol GUID. /// @@ -114,7 +114,7 @@ pub(crate) fn open_protocol<T>( Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { NonNull::new(unsafe { protocol.assume_init() }) - .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol")) + .ok_or(const_error!(io::ErrorKind::Other, "null protocol")) } } @@ -134,7 +134,7 @@ pub(crate) fn create_event( if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { - NonNull::new(event).ok_or(const_io_error!(io::ErrorKind::Other, "null protocol")) + NonNull::new(event).ok_or(const_error!(io::ErrorKind::Other, "null protocol")) } } @@ -155,10 +155,8 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result /// /// Note: Some protocols need to be manually freed. It is the caller's responsibility to do so. pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> io::Result<NonNull<T>> { - let system_handle = uefi::env::try_image_handle().ok_or(io::const_io_error!( - io::ErrorKind::NotFound, - "Protocol not found in Image handle" - ))?; + let system_handle = uefi::env::try_image_handle() + .ok_or(io::const_error!(io::ErrorKind::NotFound, "Protocol not found in Image handle"))?; open_protocol(system_handle, protocol_guid) } @@ -178,7 +176,7 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R }; let path = os_string_from_raw(path_ptr) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; if let Some(boot_services) = crate::os::uefi::env::boot_services() { let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast(); @@ -213,7 +211,7 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R } } - Err(io::const_io_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) + Err(io::const_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) } /// Gets RuntimeServices. @@ -234,7 +232,7 @@ impl DevicePath { ) -> io::Result<DevicePath> { let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>(); if path_vec[..path_vec.len() - 1].contains(&0) { - return Err(const_io_error!( + return Err(const_error!( io::ErrorKind::InvalidInput, "strings passed to UEFI cannot contain NULs", )); @@ -243,9 +241,9 @@ impl DevicePath { let path = unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) }; - NonNull::new(path).map(DevicePath).ok_or_else(|| { - const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path") - }) + NonNull::new(path) + .map(DevicePath) + .ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")) } static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> = @@ -271,7 +269,7 @@ impl DevicePath { } } - io::Result::Err(const_io_error!( + io::Result::Err(const_error!( io::ErrorKind::NotFound, "DevicePathFromText Protocol not found" )) @@ -326,7 +324,7 @@ impl<T> OwnedProtocol<T> { }; let handle = NonNull::new(handle) - .ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?; + .ok_or(io::const_error!(io::ErrorKind::Uncategorized, "found null handle"))?; Ok(Self { guid, handle, protocol }) } diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index c0ab52f650a..f29c91f3bfe 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -95,7 +95,7 @@ pub const fn unsupported<T>() -> std_io::Result<T> { #[inline] pub const fn unsupported_err() -> std_io::Error { - std_io::const_io_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI",) + std_io::const_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI",) } pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind { diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index 27395f7c3c0..6d23c72ef22 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -131,7 +131,7 @@ pub fn getcwd() -> io::Result<PathBuf> { let path_ptr = unsafe { ((*shell.as_ptr()).get_cur_dir)(crate::ptr::null_mut()) }; helpers::os_string_from_raw(path_ptr) .map(PathBuf::from) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path")) + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path")) } None => { let mut t = current_exe()?; @@ -147,7 +147,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { let shell = helpers::open_shell().ok_or(unsupported_err())?; let mut p = helpers::os_string_to_raw(p.as_os_str()) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; let r = unsafe { ((*shell.as_ptr()).set_cur_dir)(crate::ptr::null_mut(), p.as_mut_ptr()) }; if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } @@ -290,15 +290,15 @@ mod uefi_env { pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; let mut val_ptr = helpers::os_string_to_raw(val) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } } pub(crate) fn unset(key: &OsStr) -> io::Result<()> { let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } } @@ -328,7 +328,7 @@ mod uefi_env { }); // SAFETY: val.add(start) is always NULL terminated let val = unsafe { get_raw(shell, val.add(start)) } - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; vars.push((key, val)); start = i + 1; diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 1b83f4b0aee..95707ebb7f0 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -307,7 +307,7 @@ mod uefi_command_internal { use super::super::helpers; use crate::ffi::{OsStr, OsString}; - use crate::io::{self, const_io_error}; + use crate::io::{self, const_error}; use crate::mem::MaybeUninit; use crate::os::uefi::env::{boot_services, image_handle, system_table}; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; @@ -328,7 +328,7 @@ mod uefi_command_internal { pub fn load_image(p: &OsStr) -> io::Result<Self> { let path = helpers::DevicePath::from_text(p)?; let boot_services: NonNull<r_efi::efi::BootServices> = boot_services() - .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? + .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); let mut child_handle: MaybeUninit<r_efi::efi::Handle> = MaybeUninit::uninit(); let image_handle = image_handle(); @@ -369,7 +369,7 @@ mod uefi_command_internal { } let boot_services: NonNull<r_efi::efi::BootServices> = boot_services() - .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? + .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); let mut exit_data_size: usize = 0; let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit(); @@ -583,7 +583,7 @@ mod uefi_command_internal { OsString::from_wide(&self._buffer) .into_string() .map(Into::into) - .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) + .map_err(|_| const_error!(io::ErrorKind::Other, "utf8 conversion failed")) } extern "efiapi" fn reset( diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 96f99efb21e..37029bcd36e 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -559,7 +559,7 @@ impl FileAttr { return if (ext.stx_mask & libc::STATX_BTIME) != 0 { SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64) } else { - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Unsupported, "creation time is not available for the filesystem", )) @@ -567,7 +567,7 @@ impl FileAttr { } } - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Unsupported, "creation time is not available on this platform \ currently", @@ -1272,7 +1272,7 @@ impl File { target_vendor = "apple", )))] pub fn lock(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "lock() not supported")) } #[cfg(any( @@ -1293,7 +1293,7 @@ impl File { target_vendor = "apple", )))] pub fn lock_shared(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) } #[cfg(any( @@ -1320,7 +1320,7 @@ impl File { target_vendor = "apple", )))] pub fn try_lock(&self) -> io::Result<bool> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) } #[cfg(any( @@ -1347,7 +1347,7 @@ impl File { target_vendor = "apple", )))] pub fn try_lock_shared(&self) -> io::Result<bool> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) } #[cfg(any( @@ -1368,7 +1368,7 @@ impl File { target_vendor = "apple", )))] pub fn unlock(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "unlock() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "unlock() not supported")) } pub fn truncate(&self, size: u64) -> io::Result<()> { @@ -1459,11 +1459,11 @@ impl File { )))] let to_timespec = |time: Option<SystemTime>| match time { Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts), - Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!( + Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_error!( io::ErrorKind::InvalidInput, "timestamp is too large to set as a file time" )), - Some(_) => Err(io::const_io_error!( + Some(_) => Err(io::const_error!( io::ErrorKind::InvalidInput, "timestamp is too small to set as a file time" )), @@ -1476,7 +1476,7 @@ impl File { // the same as for Redox. // `futimens` and `UTIME_OMIT` are a work in progress for vxworks. let _ = times; - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Unsupported, "setting file times not supported", )) @@ -1515,7 +1515,7 @@ impl File { weak!(fn futimens(c_int, *const libc::timespec) -> c_int); match futimens.get() { Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), - None => return Err(io::const_io_error!( + None => return Err(io::const_error!( io::ErrorKind::Unsupported, "setting file times requires Android API level >= 19", )), @@ -2090,7 +2090,7 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { #[cfg(target_os = "vxworks")] pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { let (_, _, _) = (path, uid, gid); - Err(io::const_io_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) + Err(io::const_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) } #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] @@ -2101,7 +2101,7 @@ pub fn chroot(dir: &Path) -> io::Result<()> { #[cfg(target_os = "vxworks")] pub fn chroot(dir: &Path) -> io::Result<()> { let _ = dir; - Err(io::const_io_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) + Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) } pub use remove_dir_impl::remove_dir_all; diff --git a/library/std/src/sys/pal/unix/l4re.rs b/library/std/src/sys/pal/unix/l4re.rs index 52d39dcfb16..37dd370c514 100644 --- a/library/std/src/sys/pal/unix/l4re.rs +++ b/library/std/src/sys/pal/unix/l4re.rs @@ -1,6 +1,6 @@ macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, "No networking available on L4Re.", )); diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 6a67bb0a101..d140607869c 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -190,7 +190,7 @@ impl Socket { loop { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); } let timeout = timeout - elapsed; @@ -225,7 +225,7 @@ impl Socket { // for POLLHUP or POLLERR rather than read readiness if pollfd.revents & (libc::POLLHUP | libc::POLLERR) != 0 { let e = self.take_error()?.unwrap_or_else(|| { - io::const_io_error!( + io::const_error!( io::ErrorKind::Uncategorized, "no error set after POLLHUP", ) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f983d174ed6..789a40c13e6 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -258,7 +258,7 @@ pub fn current_exe() -> io::Result<PathBuf> { use crate::env; use crate::io::ErrorKind; - let exe_path = env::args().next().ok_or(io::const_io_error!( + let exe_path = env::args().next().ok_or(io::const_error!( ErrorKind::NotFound, "an executable path was not found because no arguments were provided through argv" ))?; @@ -284,7 +284,7 @@ pub fn current_exe() -> io::Result<PathBuf> { } } } - Err(io::const_io_error!(ErrorKind::NotFound, "an executable path was not found")) + Err(io::const_error!(ErrorKind::NotFound, "an executable path was not found")) } #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] @@ -340,7 +340,7 @@ pub fn current_exe() -> io::Result<PathBuf> { 0, ))?; if path_len <= 1 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Uncategorized, "KERN_PROC_PATHNAME sysctl returned zero-length string", )); @@ -363,7 +363,7 @@ pub fn current_exe() -> io::Result<PathBuf> { if curproc_exe.is_file() { return crate::fs::read_link(curproc_exe); } - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Uncategorized, "/proc/curproc/exe doesn't point to regular file.", )) @@ -382,10 +382,9 @@ pub fn current_exe() -> io::Result<PathBuf> { cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?; argv.set_len(argv_len as usize); if argv[0].is_null() { - return Err(io::const_io_error!( - io::ErrorKind::Uncategorized, - "no current exe available", - )); + return Err( + io::const_error!(io::ErrorKind::Uncategorized, "no current exe available",), + ); } let argv0 = CStr::from_ptr(argv[0]).to_bytes(); if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') { @@ -405,7 +404,7 @@ pub fn current_exe() -> io::Result<PathBuf> { ))] pub fn current_exe() -> io::Result<PathBuf> { match crate::fs::read_link("/proc/self/exe") { - Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!( + Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_error!( io::ErrorKind::Uncategorized, "no /proc/self/exe available. Is /proc mounted?", )), @@ -476,7 +475,7 @@ pub fn current_exe() -> io::Result<PathBuf> { ); if result != libc::B_OK { use crate::io::ErrorKind; - Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path")) + Err(io::const_error!(ErrorKind::Uncategorized, "Error getting executable path")) } else { // find_path adds the null terminator. let name = CStr::from_ptr(name.as_ptr()).to_bytes(); @@ -493,7 +492,7 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(target_os = "l4re")] pub fn current_exe() -> io::Result<PathBuf> { use crate::io::ErrorKind; - Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!")) + Err(io::const_error!(ErrorKind::Unsupported, "Not yet implemented!")) } #[cfg(target_os = "vxworks")] @@ -523,7 +522,7 @@ pub fn current_exe() -> io::Result<PathBuf> { use crate::env; use crate::io::ErrorKind; - let exe_path = env::args().next().ok_or(io::const_io_error!( + let exe_path = env::args().next().ok_or(io::const_error!( ErrorKind::Uncategorized, "an executable path was not found because no arguments were provided through argv" ))?; @@ -698,12 +697,82 @@ pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } } +// Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only +// used on Darwin, but should work on any unix (in case we need to get +// `_CS_PATH` or `_CS_V[67]_ENV` in the future). +// +// [posix_confstr]: +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html +// +// FIXME: Support `confstr` in Miri. +#[cfg(all(target_vendor = "apple", not(miri)))] +fn confstr(key: c_int, size_hint: Option<usize>) -> io::Result<OsString> { + let mut buf: Vec<u8> = Vec::with_capacity(0); + let mut bytes_needed_including_nul = size_hint + .unwrap_or_else(|| { + // Treat "None" as "do an extra call to get the length". In theory + // we could move this into the loop below, but it's hard to do given + // that it isn't 100% clear if it's legal to pass 0 for `len` when + // the buffer isn't null. + unsafe { libc::confstr(key, core::ptr::null_mut(), 0) } + }) + .max(1); + // If the value returned by `confstr` is greater than the len passed into + // it, then the value was truncated, meaning we need to retry. Note that + // while `confstr` results don't seem to change for a process, it's unclear + // if this is guaranteed anywhere, so looping does seem required. + while bytes_needed_including_nul > buf.capacity() { + // We write into the spare capacity of `buf`. This lets us avoid + // changing buf's `len`, which both simplifies `reserve` computation, + // allows working with `Vec<u8>` instead of `Vec<MaybeUninit<u8>>`, and + // may avoid a copy, since the Vec knows that none of the bytes are needed + // when reallocating (well, in theory anyway). + buf.reserve(bytes_needed_including_nul); + // `confstr` returns + // - 0 in the case of errors: we break and return an error. + // - The number of bytes written, iff the provided buffer is enough to + // hold the entire value: we break and return the data in `buf`. + // - Otherwise, the number of bytes needed (including nul): we go + // through the loop again. + bytes_needed_including_nul = + unsafe { libc::confstr(key, buf.as_mut_ptr().cast::<c_char>(), buf.capacity()) }; + } + // `confstr` returns 0 in the case of an error. + if bytes_needed_including_nul == 0 { + return Err(io::Error::last_os_error()); + } + // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a + // non-zero value, meaning `bytes_needed_including_nul` bytes were + // initialized. + unsafe { + buf.set_len(bytes_needed_including_nul); + // Remove the NUL-terminator. + let last_byte = buf.pop(); + // ... and smoke-check that it *was* a NUL-terminator. + assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated"); + }; + Ok(OsString::from_vec(buf)) +} + +#[cfg(all(target_vendor = "apple", not(miri)))] +fn darwin_temp_dir() -> PathBuf { + confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)).map(PathBuf::from).unwrap_or_else(|_| { + // It failed for whatever reason (there are several possible reasons), + // so return the global one. + PathBuf::from("/tmp") + }) +} + pub fn temp_dir() -> PathBuf { crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| { - if cfg!(target_os = "android") { - PathBuf::from("/data/local/tmp") - } else { - PathBuf::from("/tmp") + cfg_if::cfg_if! { + if #[cfg(all(target_vendor = "apple", not(miri)))] { + darwin_temp_dir() + } else if #[cfg(target_os = "android")] { + PathBuf::from("/data/local/tmp") + } else { + PathBuf::from("/tmp") + } } }) } diff --git a/library/std/src/sys/pal/unix/os/tests.rs b/library/std/src/sys/pal/unix/os/tests.rs index efc29955b05..63a1cc1e94a 100644 --- a/library/std/src/sys/pal/unix/os/tests.rs +++ b/library/std/src/sys/pal/unix/os/tests.rs @@ -21,3 +21,28 @@ fn test_parse_glibc_version() { assert_eq!(parsed, super::parse_glibc_version(version_str)); } } + +// Smoke check `confstr`, do it for several hint values, to ensure our resizing +// logic is correct. +#[test] +#[cfg(all(target_vendor = "apple", not(miri)))] +fn test_confstr() { + for key in [libc::_CS_DARWIN_USER_TEMP_DIR, libc::_CS_PATH] { + let value_nohint = super::confstr(key, None).unwrap_or_else(|e| { + panic!("confstr({key}, None) failed: {e:?}"); + }); + let end = (value_nohint.len() + 1) * 2; + for hint in 0..end { + assert_eq!( + super::confstr(key, Some(hint)).as_deref().ok(), + Some(&*value_nohint), + "confstr({key}, Some({hint})) failed", + ); + } + } + // Smoke check that we don't loop forever or something if the input was not valid. + for hint in [None, Some(0), Some(1)] { + let hopefully_invalid = 123456789_i32; + assert!(super::confstr(hopefully_invalid, hint).is_err()); + } +} diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index 8f7d786e32f..b7a35718757 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -18,7 +18,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "nul byte found in provided data", )); @@ -38,7 +38,7 @@ impl Command { pub fn exec(&mut self, default: Stdio) -> io::Error { if self.saw_nul() { - return io::const_io_error!( + return io::const_error!( io::ErrorKind::InvalidInput, "nul byte found in provided data", ); @@ -185,7 +185,7 @@ impl Process { ))?; } if actual != 1 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Failed to get exit status of process", )); @@ -222,7 +222,7 @@ impl Process { ))?; } if actual != 1 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Failed to get exit status of process", )); diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 8faf1fda546..ec4965c1d71 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -61,7 +61,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::InvalidInput, "nul byte found in provided data", )); @@ -175,7 +175,7 @@ impl Command { // allowed to exist in dead code), but it sounds bad, so we go out of our // way to avoid that all-together. #[cfg(any(target_os = "tvos", target_os = "watchos"))] - const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!( + const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_error!( ErrorKind::Unsupported, "`fork`+`exec`-based process spawning is not supported on this target", ); @@ -218,7 +218,7 @@ impl Command { } else if delay < MAX_FORKSPAWN_SLEEP { thread::sleep(delay); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::WouldBlock, "forking returned EBADF too often", )); @@ -235,7 +235,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data",); + return io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data",); } match self.setup_io(default, true) { @@ -561,7 +561,7 @@ impl Command { } else if delay < MAX_FORKSPAWN_SLEEP { thread::sleep(delay); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::WouldBlock, "posix_spawnp returned EBADF too often", )); diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs index 38daf6af918..e2c1b6a0326 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs @@ -22,7 +22,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::InvalidInput, "nul byte found in provided data", )); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 04024661836..131a6e81b1e 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -469,7 +469,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { unsafe { use libc::_syspage_ptr; if _syspage_ptr.is_null() { - Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available")) + Err(io::const_error!(io::ErrorKind::NotFound, "No syspage available")) } else { let cpus = (*_syspage_ptr).num_cpu; NonZero::new(cpus as usize) @@ -509,7 +509,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { } } else { // FIXME: implement on Redox, l4re - Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) } } } diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 535fe6b27d9..343864d0b3f 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -96,7 +96,7 @@ impl Timespec { if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 { Ok(unsafe { Self::new_unchecked(tv_sec, tv_nsec) }) } else { - Err(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid timestamp")) + Err(io::const_error!(io::ErrorKind::InvalidData, "Invalid timestamp")) } } diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs index 481fd62c04f..48de4312885 100644 --- a/library/std/src/sys/pal/unsupported/os.rs +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -96,11 +96,11 @@ pub fn getenv(_: &OsStr) -> Option<OsString> { } pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) } pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) } pub fn temp_dir() -> PathBuf { diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 3296c762cca..0667eb90101 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -496,7 +496,7 @@ impl File { pub fn set_times(&self, times: FileTimes) -> io::Result<()> { let to_timestamp = |time: Option<SystemTime>| match time { Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts), - Some(_) => Err(io::const_io_error!( + Some(_) => Err(io::const_error!( io::ErrorKind::InvalidInput, "timestamp is too large to set as a file time" )), @@ -764,8 +764,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> { } pub fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str() - .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) + f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) } pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { @@ -811,7 +810,7 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { for entry in ReadDir::new(fd, dummy_root) { let entry = entry?; let path = crate::str::from_utf8(&entry.name).map_err(|_| { - io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") + io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") })?; let result: io::Result<()> = try { diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/pal/wasip2/net.rs index 06e623df843..f009a51821f 100644 --- a/library/std/src/sys/pal/wasip2/net.rs +++ b/library/std/src/sys/pal/wasip2/net.rs @@ -117,7 +117,7 @@ impl Socket { loop { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); } let timeout = timeout - elapsed; diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs index e9fc19bcb99..3447a0157e4 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/pal/windows/args.rs @@ -327,7 +327,7 @@ pub(crate) fn make_bat_command_line( force_quotes: bool, ) -> io::Result<Vec<u16>> { const INVALID_ARGUMENT_ERROR: io::Error = - io::const_io_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); + io::const_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); // Set the start of the command line to `cmd.exe /c "` // It is necessary to surround the command in an extra pair of quotes, // hence the trailing quote here. It will be closed after all arguments @@ -340,7 +340,7 @@ pub(crate) fn make_bat_command_line( // Windows file names cannot contain a `"` character or end with `\\`. // If the script name does then return an error. if script.contains(&(b'"' as u16)) || script.last() == Some(&(b'\\' as u16)) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "Windows file names may not contain `\"` or end with `\\`" )); diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 07e4f93a379..5bdd5f81b9c 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -677,7 +677,7 @@ impl File { ) } _ => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Uncategorized, "Unsupported reparse point type", )); @@ -718,7 +718,7 @@ impl File { || times.modified.map_or(false, is_zero) || times.created.map_or(false, is_zero) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0", )); @@ -728,7 +728,7 @@ impl File { || times.modified.map_or(false, is_max) || times.created.map_or(false, is_max) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0xFFFF_FFFF_FFFF_FFFF", )); @@ -1305,10 +1305,9 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { #[cfg(target_vendor = "uwp")] pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { - return Err(io::const_io_error!( - io::ErrorKind::Unsupported, - "hard link are not supported on UWP", - )); + return Err( + io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP",), + ); } pub fn stat(path: &Path) -> io::Result<FileAttr> { @@ -1495,7 +1494,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { let bytes = unsafe { OsStr::from_encoded_bytes_unchecked(&abs_path[2..]) }; r"\??\UNC\".encode_utf16().chain(bytes.encode_wide()).collect() } else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, "path is not valid")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "path is not valid")); } }; // Defined inline so we don't have to mess about with variable length buffer. @@ -1512,10 +1511,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } let data_len = 12 + (abs_path.len() * 2); if data_len > u16::MAX as usize { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "`original` path is too long" - )); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long")); } let data_len = data_len as u16; let mut header = MountPointBuffer { diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index aca69490d7a..d66ff15e10b 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -183,7 +183,7 @@ pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> { maybe_result.extend(s.encode_wide()); if unrolled_find_u16s(0, &maybe_result).is_some() { - return Err(crate::io::const_io_error!( + return Err(crate::io::const_error!( ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", )); diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index fd62d1f407c..a92853c642c 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -267,7 +267,7 @@ impl Socket { }; match count { - 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")), + 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), _ => { if writefds.fd_count != 1 { if let Some(e) = self.take_error()? { diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 17bb03fe7af..da0daacd1dd 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -144,7 +144,7 @@ impl AsRef<OsStr> for EnvKey { pub(crate) fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> { if str.as_ref().encode_wide().any(|b| b == 0) { - Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) + Err(io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) } else { Ok(str) } @@ -439,10 +439,9 @@ fn resolve_exe<'a>( ) -> io::Result<Vec<u16>> { // Early return if there is no filename. if exe_path.is_empty() || path::has_trailing_slash(exe_path) { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "program path has no file name", - )); + return Err( + io::const_error!(io::ErrorKind::InvalidInput, "program path has no file name",), + ); } // Test if the file name has the `exe` extension. // This does a case-insensitive `ends_with`. @@ -492,7 +491,7 @@ fn resolve_exe<'a>( } } // If we get here then the executable cannot be found. - Err(io::const_io_error!(io::ErrorKind::NotFound, "program not found")) + Err(io::const_error!(io::ErrorKind::NotFound, "program not found")) } // Calls `f` for every path that should be used to find an executable. @@ -921,7 +920,7 @@ fn make_proc_thread_attribute_list( // a null pointer to retrieve the required size. let mut required_size = 0; let Ok(attribute_count) = attributes.len().try_into() else { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::InvalidInput, "maximum number of ProcThreadAttributes exceeded", )); diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 575f2250eb9..642c8bc4df7 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -107,7 +107,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i if data[0] >> 6 != 0b10 { // not a continuation byte - reject incomplete_utf8.len = 0; - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); @@ -129,7 +129,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i return Ok(1); } Err(_) => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); @@ -153,7 +153,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i incomplete_utf8.len = 1; return Ok(1); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); @@ -392,7 +392,7 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> { }; if result == 0 { // We can't really do any better than forget all data and return an error. - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdin in console mode does not support non-UTF-16 input; \ encountered unpaired surrogate", diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs index 1a2b56b4da5..ff6e49ed2d4 100644 --- a/library/std/src/sys/pal/xous/net/dns.rs +++ b/library/std/src/sys/pal/xous/net/dns.rs @@ -107,7 +107,7 @@ impl TryFrom<&str> for LookupHost { ($e:expr, $msg:expr) => { match $e { Some(r) => r, - None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)), + None => return Err(io::const_error!(io::ErrorKind::InvalidInput, &$msg)), } }; } @@ -123,7 +123,6 @@ impl TryFrom<(&str, u16)> for LookupHost { type Error = io::Error; fn try_from(v: (&str, u16)) -> io::Result<LookupHost> { - lookup(v.0, v.1) - .map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure")) + lookup(v.0, v.1).map_err(|_e| io::const_error!(io::ErrorKind::InvalidInput, &"DNS failure")) } } diff --git a/library/std/src/sys/pal/xous/net/tcplistener.rs b/library/std/src/sys/pal/xous/net/tcplistener.rs index ddfb289162b..640a02a64f5 100644 --- a/library/std/src/sys/pal/xous/net/tcplistener.rs +++ b/library/std/src/sys/pal/xous/net/tcplistener.rs @@ -9,7 +9,7 @@ use crate::{fmt, io}; macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, &"This function is not yet implemented", )); @@ -71,7 +71,7 @@ impl TcpListener { 0, 4096, ) else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Invalid response")); }; // The first four bytes should be zero upon success, and will be nonzero @@ -80,16 +80,13 @@ impl TcpListener { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_io_error!( - io::ErrorKind::AddrNotAvailable, - &"Invalid address" - )); + return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, &"Invalid address")); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Other, &"Unable to connect or internal error" )); @@ -130,16 +127,15 @@ impl TcpListener { if receive_request.raw[0] != 0 { // error case if receive_request.raw[1] == NetError::TimedOut as u8 { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"accept timed out",)); + return Err(io::const_error!(io::ErrorKind::TimedOut, &"accept timed out",)); } else if receive_request.raw[1] == NetError::WouldBlock as u8 { - return Err(io::const_io_error!( - io::ErrorKind::WouldBlock, - &"accept would block", - )); + return Err( + io::const_error!(io::ErrorKind::WouldBlock, &"accept would block",), + ); } else if receive_request.raw[1] == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); } } else { // accept successful @@ -163,7 +159,7 @@ impl TcpListener { port, ) } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); }; // replenish the listener @@ -175,7 +171,7 @@ impl TcpListener { Ok((TcpStream::from_listener(stream_fd, self.local.port(), port, addr), addr)) } } else { - Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unable to accept")) + Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unable to accept")) } } @@ -192,7 +188,7 @@ impl TcpListener { services::net_server(), services::NetBlockingScalar::StdSetTtlTcp(self.fd.load(Ordering::Relaxed), ttl).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -201,7 +197,7 @@ impl TcpListener { services::net_server(), services::NetBlockingScalar::StdGetTtlTcp(self.fd.load(Ordering::Relaxed)).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/library/std/src/sys/pal/xous/net/tcpstream.rs b/library/std/src/sys/pal/xous/net/tcpstream.rs index 03442cf2fcd..572dd6b3b63 100644 --- a/library/std/src/sys/pal/xous/net/tcpstream.rs +++ b/library/std/src/sys/pal/xous/net/tcpstream.rs @@ -10,7 +10,7 @@ use crate::time::Duration; macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, &"This function is not yet implemented", )); @@ -96,7 +96,7 @@ impl TcpStream { 0, 4096, ) else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Invalid response")); }; // The first four bytes should be zero upon success, and will be nonzero @@ -106,14 +106,11 @@ impl TcpStream { // errcode is a u8 but stuck in a u16 where the upper byte is invalid. Mask & decode accordingly. let errcode = response[0]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use",)); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, &"Socket in use",)); } else if errcode == NetError::Unaddressable as u8 { - return Err(io::const_io_error!( - io::ErrorKind::AddrNotAvailable, - &"Invalid address", - )); + return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, &"Invalid address",)); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Unable to connect or internal error", )); @@ -199,7 +196,7 @@ impl TcpStream { self.read_timeout.load(Ordering::Relaxed) as usize, data_to_read, ) else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Library failure: wrong message type or messaging error" )); @@ -215,14 +212,14 @@ impl TcpStream { if result[0] != 0 { if result[1] == 8 { // timed out - return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"Timeout",)); + return Err(io::const_error!(io::ErrorKind::TimedOut, &"Timeout",)); } if result[1] == 9 { // would block - return Err(io::const_io_error!(io::ErrorKind::WouldBlock, &"Would block",)); + return Err(io::const_error!(io::ErrorKind::WouldBlock, &"Would block",)); } } - Err(io::const_io_error!(io::ErrorKind::Other, &"recv_slice failure")) + Err(io::const_error!(io::ErrorKind::Other, &"recv_slice failure")) } } @@ -261,23 +258,20 @@ impl TcpStream { self.write_timeout.load(Ordering::Relaxed) as usize, buf_len, ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")))?; + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Internal error")))?; if send_request.raw[0] != 0 { if send_request.raw[4] == 8 { // timed out - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::BrokenPipe, &"Timeout or connection closed", )); } else if send_request.raw[4] == 9 { // would block - return Err(io::const_io_error!(io::ErrorKind::WouldBlock, &"Would block",)); + return Err(io::const_error!(io::ErrorKind::WouldBlock, &"Would block",)); } else { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - &"Error when sending", - )); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Error when sending",)); } } Ok(u32::from_le_bytes([ @@ -310,7 +304,7 @@ impl TcpStream { 0, 0, ) else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Internal error")); }; let mut i = get_addr.raw.iter(); match *i.next().unwrap() { @@ -330,7 +324,7 @@ impl TcpStream { } Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0))) } - _ => Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")), + _ => Err(io::const_error!(io::ErrorKind::InvalidInput, &"Internal error")), } } @@ -339,7 +333,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdTcpStreamShutdown(self.fd, how).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -361,7 +355,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdSetNodelay(self.fd, enabled).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -370,7 +364,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdGetNodelay(self.fd).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] != 0)?) } @@ -382,7 +376,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdSetTtlTcp(self.fd, ttl).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -391,7 +385,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdGetTtlTcp(self.fd).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/library/std/src/sys/pal/xous/net/udp.rs b/library/std/src/sys/pal/xous/net/udp.rs index de5133280ba..1b7ecac6d3a 100644 --- a/library/std/src/sys/pal/xous/net/udp.rs +++ b/library/std/src/sys/pal/xous/net/udp.rs @@ -11,7 +11,7 @@ use crate::{fmt, io}; macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, &"This function is not yet implemented", )); @@ -72,16 +72,16 @@ impl UdpSocket { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Port can't be 0 or invalid address" )); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Other, &"Unable to connect or internal error" )); @@ -98,13 +98,13 @@ impl UdpSocket { nonblocking: Cell::new(false), }); } - Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")) + Err(io::const_error!(io::ErrorKind::InvalidInput, &"Invalid response")) } pub fn peer_addr(&self) -> io::Result<SocketAddr> { match self.remote.get() { Some(dest) => Ok(dest), - None => Err(io::const_io_error!(io::ErrorKind::NotConnected, &"No peer specified")), + None => Err(io::const_error!(io::ErrorKind::NotConnected, &"No peer specified")), } } @@ -141,16 +141,13 @@ impl UdpSocket { if receive_request.raw[0] != 0 { // error case if receive_request.raw[1] == NetError::TimedOut as u8 { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"recv timed out",)); + return Err(io::const_error!(io::ErrorKind::TimedOut, &"recv timed out",)); } else if receive_request.raw[1] == NetError::WouldBlock as u8 { - return Err(io::const_io_error!( - io::ErrorKind::WouldBlock, - &"recv would block", - )); + return Err(io::const_error!(io::ErrorKind::WouldBlock, &"recv would block",)); } else if receive_request.raw[1] == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); } } else { let rr = &receive_request.raw; @@ -173,7 +170,7 @@ impl UdpSocket { port, ) } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); }; for (&s, d) in rr[22..22 + rxlen as usize].iter().zip(buf.iter_mut()) { *d = s; @@ -181,7 +178,7 @@ impl UdpSocket { Ok((rxlen as usize, addr)) } } else { - Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unable to recv")) + Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unable to recv")) } } @@ -211,7 +208,7 @@ impl UdpSocket { if let Some(addr) = self.remote.get() { self.send_to(buf, &addr) } else { - Err(io::const_io_error!(io::ErrorKind::NotConnected, &"No remote specified")) + Err(io::const_error!(io::ErrorKind::NotConnected, &"No remote specified")) } } @@ -282,22 +279,19 @@ impl UdpSocket { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::ResourceBusy, &"Socket in use" )); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Socket not valid" )); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_io_error!( - io::ErrorKind::Other, - &"Library error" - )); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Other, &"Unable to connect" )); @@ -309,7 +303,7 @@ impl UdpSocket { } Err(crate::os::xous::ffi::Error::ServerQueueFull) => { if now.elapsed() >= write_timeout { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::WouldBlock, &"Write timed out" )); @@ -318,7 +312,7 @@ impl UdpSocket { crate::thread::yield_now(); } } - _ => return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")), + _ => return Err(io::const_error!(io::ErrorKind::Other, &"Library error")), } } } @@ -372,7 +366,7 @@ impl UdpSocket { services::net_server(), services::NetBlockingScalar::StdSetTtlUdp(self.fd, ttl).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -381,7 +375,7 @@ impl UdpSocket { services::net_server(), services::NetBlockingScalar::StdGetTtlUdp(self.fd).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index 5d224ffd1ba..868b19e33b6 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -115,11 +115,11 @@ pub fn getenv(varname: &OsStr) -> Option<OsString> { } pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) } pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) } pub fn temp_dir() -> PathBuf { diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 9267602cb97..de042fa3f82 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -328,7 +328,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { if prefix.map(|x| x.is_verbatim()).unwrap_or(false) { // NULs in verbatim paths are rejected for consistency. if path.as_encoded_bytes().contains(&0) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", )); diff --git a/library/std/src/sys/random/arc4random.rs b/library/std/src/sys/random/arc4random.rs index ffabaafbee8..32467e9ebaa 100644 --- a/library/std/src/sys/random/arc4random.rs +++ b/library/std/src/sys/random/arc4random.rs @@ -12,7 +12,6 @@ #[cfg(not(any( target_os = "haiku", target_os = "illumos", - target_os = "rtems", target_os = "solaris", target_os = "vita", )))] @@ -22,7 +21,6 @@ use libc::arc4random_buf; #[cfg(any( target_os = "haiku", // See https://git.haiku-os.org/haiku/tree/headers/compatibility/bsd/stdlib.h target_os = "illumos", // See https://www.illumos.org/man/3C/arc4random - target_os = "rtems", // See https://docs.rtems.org/branches/master/bsp-howto/getentropy.html target_os = "solaris", // See https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74 ))] diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 177d0d7744a..87837915b39 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -93,7 +93,7 @@ const QUEUE_MASK: usize = !STATE_MASK; // use interior mutability. #[repr(align(4))] // Ensure the two lower bits are free to use as state bits. struct Waiter { - thread: Cell<Option<Thread>>, + thread: Thread, signaled: AtomicBool, next: Cell<*const Waiter>, } @@ -238,7 +238,7 @@ fn wait( return_on_poisoned: bool, ) -> StateAndQueue { let node = &Waiter { - thread: Cell::new(Some(thread::current())), + thread: thread::current_or_unnamed(), signaled: AtomicBool::new(false), next: Cell::new(ptr::null()), }; @@ -277,7 +277,8 @@ fn wait( // can park ourselves, the result could be this thread never gets // unparked. Luckily `park` comes with the guarantee that if it got // an `unpark` just before on an unparked thread it does not park. - thread::park(); + // SAFETY: we retrieved this handle on the current thread above. + unsafe { node.thread.park() } } return state_and_queue.load(Acquire); @@ -309,7 +310,7 @@ impl Drop for WaiterQueue<'_> { let mut queue = to_queue(current); while !queue.is_null() { let next = (*queue).next.get(); - let thread = (*queue).thread.take().unwrap(); + let thread = (*queue).thread.clone(); (*queue).signaled.store(true, Release); thread.unpark(); queue = next; diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 51330f8fafe..bd15f8ee952 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -118,7 +118,7 @@ use crate::mem; use crate::ptr::{self, NonNull, null_mut, without_provenance_mut}; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicBool, AtomicPtr}; -use crate::thread::{self, Thread, ThreadId}; +use crate::thread::{self, Thread}; /// The atomic lock state. type AtomicState = AtomicPtr<()>; @@ -217,9 +217,7 @@ impl Node { /// Prepare this node for waiting. fn prepare(&mut self) { // Fall back to creating an unnamed `Thread` handle to allow locking in TLS destructors. - self.thread.get_or_init(|| { - thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new())) - }); + self.thread.get_or_init(thread::current_or_unnamed); self.completed = AtomicBool::new(false); } diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index a25a7244660..bfd684d295b 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -5,7 +5,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::path::Path; use crate::sys_common::ignore_notfound; -pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!( +pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( ErrorKind::InvalidInput, "the source path is neither a regular file nor a symlink to a regular file", ); diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 5a0ad907581..74306978d22 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -122,7 +122,7 @@ pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result *(storage as *const _ as *const c::sockaddr_in6) }))) } - _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument")), + _ => Err(io::const_error!(ErrorKind::InvalidInput, "invalid argument")), } } @@ -185,7 +185,7 @@ impl TryFrom<&str> for LookupHost { ($e:expr, $msg:expr) => { match $e { Some(r) => r, - None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)), + None => return Err(io::const_error!(io::ErrorKind::InvalidInput, $msg)), } }; } diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs index e6eb90c4c30..1048ef97356 100644 --- a/library/std/src/thread/current.rs +++ b/library/std/src/thread/current.rs @@ -165,6 +165,23 @@ pub(crate) fn try_current() -> Option<Thread> { } } +/// Gets a handle to the thread that invokes it. If the handle stored in thread- +/// local storage was already destroyed, this creates a new unnamed temporary +/// handle to allow thread parking in nearly all situations. +pub(crate) fn current_or_unnamed() -> Thread { + let current = CURRENT.get(); + if current > DESTROYED { + unsafe { + let current = ManuallyDrop::new(Thread::from_raw(current)); + (*current).clone() + } + } else if current == DESTROYED { + Thread::new_unnamed(id::get_or_init()) + } else { + init_current(current) + } +} + /// Gets a handle to the thread that invokes it. /// /// # Examples @@ -226,17 +243,17 @@ fn init_current(current: *mut ()) -> Thread { // a particular API should be entirely allocation-free, feel free to open // an issue on the Rust repository, we'll see what we can do. rtabort!( - "\n - Attempted to access thread-local data while allocating said data.\n - Do not access functions that allocate in the global allocator!\n - This is a bug in the global allocator.\n - " + "\n\ + Attempted to access thread-local data while allocating said data.\n\ + Do not access functions that allocate in the global allocator!\n\ + This is a bug in the global allocator.\n\ + " ) } else { debug_assert_eq!(current, DESTROYED); panic!( - "use of std::thread::current() is not possible after the thread's - local data has been destroyed" + "use of std::thread::current() is not possible after the thread's \ + local data has been destroyed" ) } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 9edb3fa4193..bc5f701e346 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -252,6 +252,19 @@ impl<T: 'static> LocalKey<T> { /// This function will `panic!()` if the key currently has its /// destructor running, and it **may** panic if the destructor has /// previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// thread_local! { + /// pub static STATIC: String = String::from("I am"); + /// } + /// + /// assert_eq!( + /// STATIC.with(|original_value| format!("{original_value} initialized")), + /// "I am initialized", + /// ); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with<F, R>(&'static self, f: F) -> R where @@ -273,6 +286,19 @@ impl<T: 'static> LocalKey<T> { /// /// This function will still `panic!()` if the key is uninitialized and the /// key's initializer panics. + /// + /// # Examples + /// + /// ``` + /// thread_local! { + /// pub static STATIC: String = String::from("I am"); + /// } + /// + /// assert_eq!( + /// STATIC.try_with(|original_value| format!("{original_value} initialized")), + /// Ok(String::from("I am initialized")), + /// ); + /// ``` #[stable(feature = "thread_local_try_with", since = "1.26.0")] #[inline] pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> @@ -452,7 +478,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// Panics if the key currently has its destructor running, /// and it **may** panic if the destructor has previously been run for this thread. /// - /// # Example + /// # Examples /// /// ``` /// use std::cell::RefCell; @@ -483,7 +509,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// Panics if the key currently has its destructor running, /// and it **may** panic if the destructor has previously been run for this thread. /// - /// # Example + /// # Examples /// /// ``` /// use std::cell::RefCell; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 2c2cc58a9dd..2ff44fcd4c6 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -186,7 +186,7 @@ mod current; #[stable(feature = "rust1", since = "1.0.0")] pub use current::current; -pub(crate) use current::{current_id, drop_current, set_current, try_current}; +pub(crate) use current::{current_id, current_or_unnamed, drop_current, set_current, try_current}; mod spawnhook; @@ -1146,9 +1146,9 @@ pub fn park_timeout_ms(ms: u32) { #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { let guard = PanicGuard; - // SAFETY: park_timeout is called on the parker owned by this thread. + // SAFETY: park_timeout is called on a handle owned by this thread. unsafe { - current().0.parker().park_timeout(dur); + current().park_timeout(dur); } // No panic occurred, do not abort. forget(guard); @@ -1446,6 +1446,15 @@ impl Thread { unsafe { self.0.parker().park() } } + /// Like the public [`park_timeout`], but callable on any handle. This is + /// used to allow parking in TLS destructors. + /// + /// # Safety + /// May only be called from the thread to which this handle belongs. + pub(crate) unsafe fn park_timeout(&self, dur: Duration) { + unsafe { self.0.parker().park_timeout(dur) } + } + /// Atomically makes the handle's token available if it is not already. /// /// Every thread is equipped with some basic low-level blocking support, via diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index b2305b1eda7..0033fc3a732 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -1,4 +1,4 @@ -use super::{Builder, JoinInner, Result, Thread, current, park}; +use super::{Builder, JoinInner, Result, Thread, current_or_unnamed}; use crate::marker::PhantomData; use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use crate::sync::Arc; @@ -140,7 +140,7 @@ where let scope = Scope { data: Arc::new(ScopeData { num_running_threads: AtomicUsize::new(0), - main_thread: current(), + main_thread: current_or_unnamed(), a_thread_panicked: AtomicBool::new(false), }), env: PhantomData, @@ -152,7 +152,8 @@ where // Wait until all the threads are finished. while scope.data.num_running_threads.load(Ordering::Acquire) != 0 { - park(); + // SAFETY: this is the main thread, the handle belongs to us. + unsafe { scope.data.main_thread.park() }; } // Throw any panic from `f`, or the return value of `f` if no thread panicked. @@ -176,7 +177,7 @@ impl<'scope, 'env> Scope<'scope, 'env> { /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing /// the panic payload. /// - /// If the join handle is dropped, the spawned thread will implicitly joined at the + /// If the join handle is dropped, the spawned thread will be implicitly joined at the /// end of the scope. In that case, if the spawned thread panics, [`scope`] will /// panic after all threads are joined. /// |
