diff options
Diffstat (limited to 'library/std/src')
38 files changed, 381 insertions, 367 deletions
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 53b43455b5a..c0524352193 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -371,7 +371,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(vec, ["a", "b", "c"]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_keys(self) -> IntoKeys<K, V> { IntoKeys { inner: self.into_iter() } @@ -449,7 +449,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(vec, [1, 2, 3]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_values(self) -> IntoValues<K, V> { IntoValues { inner: self.into_iter() } @@ -473,7 +473,7 @@ impl<K, V, S> HashMap<K, V, S> { /// println!("key: {} val: {}", key, val); /// } /// ``` - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { Iter { base: self.base.iter() } @@ -503,7 +503,7 @@ impl<K, V, S> HashMap<K, V, S> { /// println!("key: {} val: {}", key, val); /// } /// ``` - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { IterMut { base: self.base.iter_mut() } @@ -568,7 +568,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert!(a.is_empty()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, K, V> { Drain { base: self.base.drain() } @@ -610,7 +610,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[unstable(feature = "hash_drain_filter", issue = "59618")] pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F> where @@ -634,7 +634,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(map.len(), 4); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "retain_hash_collection", since = "1.18.0")] pub fn retain<F>(&mut self, f: F) where @@ -2001,7 +2001,7 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> { type IntoIter = Iter<'a, K, V>; #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> Iter<'a, K, V> { self.iter() } @@ -2013,7 +2013,7 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> { type IntoIter = IterMut<'a, K, V>; #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> IterMut<'a, K, V> { self.iter_mut() } @@ -2043,7 +2043,7 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S> { /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> IntoIter<K, V> { IntoIter { base: self.base.into_iter() } } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 200667ae390..2eb4cacabb8 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -185,7 +185,7 @@ impl<T, S> HashSet<T, S> { /// } /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, T> { Iter { base: self.base.iter() } @@ -250,7 +250,7 @@ impl<T, S> HashSet<T, S> { /// assert!(set.is_empty()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, T> { Drain { base: self.base.drain() } @@ -289,7 +289,7 @@ impl<T, S> HashSet<T, S> { /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[unstable(feature = "hash_drain_filter", issue = "59618")] pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F> where @@ -312,7 +312,7 @@ impl<T, S> HashSet<T, S> { /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "retain_hash_collection", since = "1.18.0")] pub fn retain<F>(&mut self, f: F) where @@ -537,7 +537,7 @@ where /// assert_eq!(diff, [4].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> { Difference { iter: self.iter(), other } @@ -565,7 +565,7 @@ where /// assert_eq!(diff1, [1, 4].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn symmetric_difference<'a>( &'a self, @@ -593,7 +593,7 @@ where /// assert_eq!(intersection, [2, 3].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> { if self.len() <= other.len() { @@ -622,7 +622,7 @@ where /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> { if self.len() >= other.len() { @@ -1423,7 +1423,7 @@ impl<'a, T, S> IntoIterator for &'a HashSet<T, S> { type IntoIter = Iter<'a, T>; #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> Iter<'a, T> { self.iter() } @@ -1455,7 +1455,7 @@ impl<T, S> IntoIterator for HashSet<T, S> { /// } /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> IntoIter<T> { IntoIter { base: self.base.into_iter() } } diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 019b64c395e..13e3dacc30d 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -159,6 +159,15 @@ pub use self::os_str::{OsStr, OsString}; #[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; +#[unstable(feature = "core_ffi_c", issue = "94501")] +pub use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, +}; + +#[unstable(feature = "c_size_t", issue = "88345")] +pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t}; + #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 1aa6d657889..17e2b97545a 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -141,6 +141,19 @@ struct Custom { /// It is used with the [`io::Error`] type. /// /// [`io::Error`]: Error +/// +/// # Handling errors and matching on `ErrorKind` +/// +/// In application code, use `match` for the `ErrorKind` values you are +/// expecting; use `_` to match "all other errors". +/// +/// In comprehensive and thorough tests that want to verify that a test doesn't +/// return any known incorrect error kind, you may want to cut-and-paste the +/// current full list of errors from here into your test code, and then match +/// `_` as the correct case. This seems counterintuitive, but it will make your +/// tests more robust. In particular, if you want to verify that your code does +/// produce an unrecognized error kind, the robust solution is to check for all +/// the recognized error kinds and fail in those cases. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 35d230eee96..5b76259afc1 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2203,17 +2203,18 @@ mod where_keyword {} /// /// Use `async` in front of `fn`, `closure`, or a `block` to turn the marked code into a `Future`. /// As such the code will not be run immediately, but will only be evaluated when the returned -/// future is `.await`ed. +/// future is [`.await`]ed. /// -/// We have written an [async book] detailing async/await and trade-offs compared to using threads. +/// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. /// /// ## Editions /// /// `async` is a keyword from the 2018 edition onwards. /// -/// It is available for use in stable rust from version 1.39 onwards. +/// It is available for use in stable Rust from version 1.39 onwards. /// /// [`Future`]: future::Future +/// [`.await`]: ../std/keyword.await.html /// [async book]: https://rust-lang.github.io/async-book/ mod async_keyword {} @@ -2221,19 +2222,20 @@ mod async_keyword {} // /// Suspend execution until the result of a [`Future`] is ready. /// -/// `.await`ing a future will suspend the current function's execution until the `executor` +/// `.await`ing a future will suspend the current function's execution until the executor /// has run the future to completion. /// -/// Read the [async book] for details on how async/await and executors work. +/// Read the [async book] for details on how [`async`]/`await` and executors work. /// /// ## Editions /// /// `await` is a keyword from the 2018 edition onwards. /// -/// It is available for use in stable rust from version 1.39 onwards. +/// It is available for use in stable Rust from version 1.39 onwards. /// /// [`Future`]: future::Future /// [async book]: https://rust-lang.github.io/async-book/ +/// [`async`]: ../std/keyword.async.html mod await_keyword {} #[doc(keyword = "dyn")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 2628afd4237..10fec8e1152 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -243,7 +243,6 @@ #![feature(c_variadic)] #![feature(cfg_accessible)] #![feature(cfg_eval)] -#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(char_internals)] @@ -262,6 +261,8 @@ #![feature(const_socketaddr)] #![feature(const_trait_impl)] #![feature(container_error_extra)] +#![feature(c_size_t)] +#![feature(core_ffi_c)] #![feature(core_intrinsics)] #![feature(core_panic)] #![feature(custom_test_frameworks)] @@ -316,6 +317,7 @@ #![feature(prelude_import)] #![feature(ptr_as_uninit)] #![feature(ptr_internals)] +#![feature(raw_os_nonzero)] #![feature(rustc_attrs)] #![feature(rustc_private)] #![feature(saturating_int_impl)] @@ -366,6 +368,7 @@ extern crate unwind; #[doc(masked)] #[allow(unused_extern_crates)] +#[cfg(feature = "miniz_oxide")] extern crate miniz_oxide; // During testing, this crate is not actually the "real" std library, but rather diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs index df11dc21aa7..13bb079194f 100644 --- a/library/std/src/os/fd/mod.rs +++ b/library/std/src/os/fd/mod.rs @@ -11,3 +11,6 @@ pub mod owned; // Implementations for `AsRawFd` etc. for network types. mod net; + +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 71c660e7186..807b057234a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,7 +8,7 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "wasi", target_env = "sgx")))] use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -21,6 +21,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// descriptor, so it can be used in FFI in places where a file descriptor is /// passed as an argument, it is not captured or consumed, and it never has the /// value `-1`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedFd` +/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file +/// descriptor, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -62,7 +66,7 @@ impl BorrowedFd<'_> { /// the returned `BorrowedFd`, and it must not have the value `-1`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { + pub unsafe fn borrow_raw(fd: RawFd) -> Self { assert_ne!(fd, u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) unsafe { Self { fd, _phantom: PhantomData } } @@ -231,7 +235,7 @@ impl AsFd for OwnedFd { // Safety: `OwnedFd` and `BorrowedFd` have the same validity // invariants, and the `BorrowdFd` is bounded by the lifetime // of `&self`. - unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } } } diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index f874cf0b42d..f9c883dd6bf 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -5,6 +5,8 @@ use crate::fs; use crate::io; use crate::os::raw; +#[cfg(doc)] +use crate::os::unix::io::AsFd; #[cfg(unix)] use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] @@ -24,9 +26,14 @@ pub type RawFd = raw::c_int; pub trait AsRawFd { /// Extracts the raw file descriptor. /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. + /// This function is typically used to **borrow** an owned file descriptor. + /// When used in this way, this method does **not** pass ownership of the + /// raw file descriptor to the caller, and the file descriptor is only + /// guaranteed to be valid while the original object has not yet been + /// destroyed. + /// + /// However, borrowing is not strictly required. See [`AsFd::as_fd`] + /// for an API which strictly borrows a file descriptor. /// /// # Example /// @@ -55,15 +62,18 @@ pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file /// descriptor. /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. + /// This function is typically used to **consume ownership** of the + /// specified file descriptor. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// [`From<OwnedFd>::from`] implementation for an API which strictly + /// consumes ownership. /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// # Safety + /// + /// The `fd` passed in must be a valid an open file descriptor. /// /// # Example /// @@ -94,9 +104,13 @@ pub trait FromRawFd { pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. + /// This function is typically used to **transfer ownership** of the underlying + /// file descriptor to the caller. When used in this way, callers are then the unique + /// owners of the file descriptor and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// [`Into<OwnedFd>::into`] implementation for an API which strictly + /// transfers ownership. /// /// # Example /// diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs new file mode 100644 index 00000000000..26ef93e3d71 --- /dev/null +++ b/library/std/src/os/fd/tests.rs @@ -0,0 +1,34 @@ +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_raw_fd() { + #[cfg(unix)] + use crate::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; + + let raw_fd: RawFd = crate::io::stdin().as_raw_fd(); + + let stdin_as_file = unsafe { crate::fs::File::from_raw_fd(raw_fd) }; + assert_eq!(stdin_as_file.as_raw_fd(), raw_fd); + assert_eq!(unsafe { BorrowedFd::borrow_raw(raw_fd).as_raw_fd() }, raw_fd); + assert_eq!(stdin_as_file.into_raw_fd(), 0); +} + +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_fd() { + #[cfg(unix)] + use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + + let stdin = crate::io::stdin(); + let fd: BorrowedFd<'_> = stdin.as_fd(); + let raw_fd: RawFd = fd.as_raw_fd(); + let owned_fd: OwnedFd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; + + let stdin_as_file = crate::fs::File::from(owned_fd); + + assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd); + assert_eq!(Into::<OwnedFd>::into(stdin_as_file).into_raw_fd(), raw_fd); +} diff --git a/library/std/src/os/raw/char.md b/library/std/src/os/raw/char.md deleted file mode 100644 index 375d070516e..00000000000 --- a/library/std/src/os/raw/char.md +++ /dev/null @@ -1,9 +0,0 @@ -Equivalent to C's `char` type. - -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes. - -C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. - -[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types -[Rust's `char` type]: char -[`CStr`]: crate::ffi::CStr diff --git a/library/std/src/os/raw/double.md b/library/std/src/os/raw/double.md deleted file mode 100644 index 57f4534829e..00000000000 --- a/library/std/src/os/raw/double.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `double` type. - -This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. - -[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 -[`float`]: c_float diff --git a/library/std/src/os/raw/float.md b/library/std/src/os/raw/float.md deleted file mode 100644 index 61e2abc0518..00000000000 --- a/library/std/src/os/raw/float.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `float` type. - -This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. - -[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 diff --git a/library/std/src/os/raw/int.md b/library/std/src/os/raw/int.md deleted file mode 100644 index 8062ff2307a..00000000000 --- a/library/std/src/os/raw/int.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed int` (`int`) type. - -This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example. - -[`short`]: c_short diff --git a/library/std/src/os/raw/long.md b/library/std/src/os/raw/long.md deleted file mode 100644 index cc160783f78..00000000000 --- a/library/std/src/os/raw/long.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed long` (`long`) type. - -This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`. - -[`int`]: c_int diff --git a/library/std/src/os/raw/longlong.md b/library/std/src/os/raw/longlong.md deleted file mode 100644 index 49c61bd61f4..00000000000 --- a/library/std/src/os/raw/longlong.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed long long` (`long long`) type. - -This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type. - -[`long`]: c_int diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index b6d5199341c..19d0ffb2e39 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -1,156 +1,31 @@ -//! Platform-specific types, as defined by C. -//! -//! Code that interacts via FFI will almost certainly be using the -//! base types provided by C, which aren't nearly as nicely defined -//! as Rust's primitive types. This module provides types which will -//! match those defined by C, so that code that interacts with C will -//! refer to the correct types. +//! Compatibility module for C platform-specific types. Use [`core::ffi`] instead. #![stable(feature = "raw_os", since = "1.1.0")] #[cfg(test)] mod tests; -use core::num::*; - -macro_rules! type_alias_no_nz { - { - $Docfile:tt, $Alias:ident = $Real:ty; - $( $Cfg:tt )* - } => { - #[doc = include_str!($Docfile)] - $( $Cfg )* +macro_rules! alias_core_ffi { + ($($t:ident)*) => {$( #[stable(feature = "raw_os", since = "1.1.0")] - pub type $Alias = $Real; - } -} - -// To verify that the NonZero types in this file's macro invocations correspond -// -// perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2' -// -// NB this does not check that the main c_* types are right. - -macro_rules! type_alias { - { - $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty; - $( $Cfg:tt )* - } => { - type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* } - - #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")] - #[unstable(feature = "raw_os_nonzero", issue = "82363")] - $( $Cfg )* - pub type $NZAlias = $NZReal; - } + #[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))] + // Make this type alias appear cfg-dependent so that Clippy does not suggest + // replacing expressions like `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be + // removed after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 + // is fixed. + #[cfg(all())] + #[doc(cfg(all()))] + pub type $t = core::ffi::$t; + )*} } -type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char; -// Make this type alias appear cfg-dependent so that Clippy does not suggest -// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed -// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 -// is fixed. -#[cfg(all())] -#[doc(cfg(all()))] } -type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; } -type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; } -type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; } -type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } -type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } -type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } -type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; -#[doc(cfg(all()))] -#[cfg(any(target_pointer_width = "32", windows))] } -type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; -#[doc(cfg(all()))] -#[cfg(any(target_pointer_width = "32", windows))] } -type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; -#[doc(cfg(all()))] -#[cfg(all(target_pointer_width = "64", not(windows)))] } -type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; -#[doc(cfg(all()))] -#[cfg(all(target_pointer_width = "64", not(windows)))] } -type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } -type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } -type_alias_no_nz! { "float.md", c_float = f32; } -type_alias_no_nz! { "double.md", c_double = f64; } - -#[stable(feature = "raw_os", since = "1.1.0")] -#[doc(no_inline)] -pub use core::ffi::c_void; - -/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++). -/// -/// This type is currently always [`usize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_size_t = usize; - -/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++). -/// -/// This type is currently always [`isize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_ptrdiff_t = isize; - -/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type. -/// -/// This type is currently always [`isize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_ssize_t = isize; - -mod c_char_definition { - cfg_if::cfg_if! { - // These are the targets on which c_char is unsigned. - if #[cfg(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - target_os = "freebsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") - ), - all(target_os = "openbsd", target_arch = "aarch64"), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all(target_os = "fuchsia", target_arch = "aarch64") - ))] { - pub type c_char = u8; - pub type NonZero_c_char = core::num::NonZeroU8; - } else { - // On every other target, c_char is signed. - pub type c_char = i8; - pub type NonZero_c_char = core::num::NonZeroI8; - } - } +alias_core_ffi! { + c_char c_schar c_uchar + c_short c_ushort + c_int c_uint + c_long c_ulong + c_longlong c_ulonglong + c_float + c_double + c_void } diff --git a/library/std/src/os/raw/schar.md b/library/std/src/os/raw/schar.md deleted file mode 100644 index 69879c9f17f..00000000000 --- a/library/std/src/os/raw/schar.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed char` type. - -This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`]. - -[`char`]: c_char diff --git a/library/std/src/os/raw/short.md b/library/std/src/os/raw/short.md deleted file mode 100644 index 3d1e53d1325..00000000000 --- a/library/std/src/os/raw/short.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed short` (`short`) type. - -This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example. - -[`char`]: c_char diff --git a/library/std/src/os/raw/uchar.md b/library/std/src/os/raw/uchar.md deleted file mode 100644 index b633bb7f8da..00000000000 --- a/library/std/src/os/raw/uchar.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned char` type. - -This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`]. - -[`char`]: c_char diff --git a/library/std/src/os/raw/uint.md b/library/std/src/os/raw/uint.md deleted file mode 100644 index f3abea35937..00000000000 --- a/library/std/src/os/raw/uint.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned int` type. - -This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. - -[`int`]: c_int diff --git a/library/std/src/os/raw/ulong.md b/library/std/src/os/raw/ulong.md deleted file mode 100644 index 4ab304e6577..00000000000 --- a/library/std/src/os/raw/ulong.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned long` type. - -This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`. - -[`long`]: c_long diff --git a/library/std/src/os/raw/ulonglong.md b/library/std/src/os/raw/ulonglong.md deleted file mode 100644 index a27d70e1753..00000000000 --- a/library/std/src/os/raw/ulonglong.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned long long` type. - -This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type. - -[`long long`]: c_longlong diff --git a/library/std/src/os/raw/ushort.md b/library/std/src/os/raw/ushort.md deleted file mode 100644 index 6928e51b352..00000000000 --- a/library/std/src/os/raw/ushort.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned short` type. - -This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`]. - -[`short`]: c_short diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 8df6c54a414..d378d591ba3 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -28,6 +28,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. /// +/// This type's `.to_owned()` implementation returns another `BorrowedHandle` +/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw +/// handle, which is then borrowed under the same lifetime. +/// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[derive(Copy, Clone)] #[repr(transparent)] @@ -131,7 +135,7 @@ impl BorrowedHandle<'_> { /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn borrow_raw(handle: RawHandle) -> Self { Self { handle, _phantom: PhantomData } } } @@ -210,29 +214,13 @@ impl IntoRawHandle for OwnedHandle { } impl FromRawHandle for OwnedHandle { - /// Constructs a new instance of `Self` from the given raw handle. - /// - /// # Safety - /// - /// The resource pointed to by `handle` must be open and suitable for - /// assuming ownership. The resource must not require any cleanup other - /// than `CloseHandle`. - /// - /// In particular, it must not be used with handles to open registry - /// keys which need to be closed with [`RegCloseKey`] instead. - /// - /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is - /// sometimes a valid handle value. See [here] for the full story. - /// - /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey - /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self { handle } } } -impl FromRawHandle for HandleOrNull { +impl HandleOrNull { /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses null to indicate failure, such as /// `CreateThread`. @@ -242,18 +230,18 @@ impl FromRawHandle for HandleOrNull { /// /// # Safety /// - /// The resource pointed to by `handle` must be either open and otherwise - /// unowned, or null. Note that not all Windows APIs use null for errors; - /// see [here] for the full story. + /// The passed `handle` value must either satisfy the safety requirements + /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all + /// Windows APIs use null for errors; see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] - unsafe fn from_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self(OwnedHandle::from_raw_handle(handle)) } } -impl FromRawHandle for HandleOrInvalid { +impl HandleOrInvalid { /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate /// failure, such as `CreateFileW`. @@ -263,14 +251,14 @@ impl FromRawHandle for HandleOrInvalid { /// /// # Safety /// - /// The resource pointed to by `handle` must be either open and otherwise - /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not - /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for - /// the full story. + /// The passed `handle` value must either satisfy the safety requirements + /// of [`FromRawHandle::from_raw_handle`], or be + /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use + /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] - unsafe fn from_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self(OwnedHandle::from_raw_handle(handle)) } } @@ -345,7 +333,7 @@ impl AsHandle for OwnedHandle { // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity // invariants, and the `BorrowdHandle` is bounded by the lifetime // of `&self`. - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -373,49 +361,49 @@ impl From<OwnedHandle> for fs::File { impl AsHandle for crate::io::Stdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StdinLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::io::Stdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StdoutLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::io::Stderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StderrLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::process::ChildStdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -429,7 +417,7 @@ impl From<crate::process::ChildStdin> for OwnedHandle { impl AsHandle for crate::process::ChildStdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -443,7 +431,7 @@ impl From<crate::process::ChildStdout> for OwnedHandle { impl AsHandle for crate::process::ChildStderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -457,7 +445,7 @@ impl From<crate::process::ChildStderr> for OwnedHandle { impl<T> AsHandle for crate::thread::JoinHandle<T> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index c7f122048a1..48c5fd358d9 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -5,6 +5,8 @@ use crate::fs; use crate::io; use crate::net; +#[cfg(doc)] +use crate::os::windows::io::{AsHandle, AsSocket}; use crate::os::windows::io::{OwnedHandle, OwnedSocket}; use crate::os::windows::raw; use crate::sys; @@ -22,7 +24,15 @@ pub type RawSocket = raw::SOCKET; /// Extracts raw handles. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawHandle { - /// Extracts the raw handle, without taking any ownership. + /// Extracts the raw handle. + /// + /// This function is typically used to **borrow** an owned handle. + /// When used in this way, this method does **not** pass ownership of the + /// raw handle to the caller, and the handle is only guaranteed + /// to be valid while the original object has not yet been destroyed. + /// + /// However, borrowing is not strictly required. See [`AsHandle::as_handle`] + /// for an API which strictly borrows a handle. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_handle(&self) -> RawHandle; } @@ -32,15 +42,28 @@ pub trait AsRawHandle { pub trait FromRawHandle { /// Constructs a new I/O object from the specified raw handle. /// - /// This function will **consume ownership** of the handle given, - /// passing responsibility for closing the handle to the returned - /// object. + /// This function is typically used to **consume ownership** of the handle + /// given, passing responsibility for closing the handle to the returned + /// object. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// `From<OwnedHandle>::from` implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// The `handle` passed in must: + /// - be a valid an open handle, + /// - be a handle for a resource that may be freed via [`CloseHandle`] + /// (as opposed to `RegCloseKey` or other close functions). + /// + /// Note that the handle *may* have the value `INVALID_HANDLE_VALUE` (-1), + /// which is sometimes a valid handle value. See [here] for the full story. + /// + /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_handle(handle: RawHandle) -> Self; } @@ -51,9 +74,13 @@ pub trait FromRawHandle { pub trait IntoRawHandle { /// Consumes this object, returning the raw underlying handle. /// - /// This function **transfers ownership** of the underlying handle to the - /// caller. Callers are then the unique owners of the handle and must close - /// it once it's no longer needed. + /// This function is typically used to **transfer ownership** of the underlying + /// handle to the caller. When used in this way, callers are then the unique + /// owners of the handle and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// `Into<OwnedHandle>::into` implementation for an API which strictly + /// transfers ownership. #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_handle(self) -> RawHandle; } @@ -130,7 +157,15 @@ impl IntoRawHandle for fs::File { /// Extracts raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { - /// Extracts the underlying raw socket from this object. + /// Extracts the raw socket. + /// + /// This function is typically used to **borrow** an owned socket. + /// When used in this way, this method does **not** pass ownership of the + /// raw socket to the caller, and the socket is only guaranteed + /// to be valid while the original object has not yet been destroyed. + /// + /// However, borrowing is not strictly required. See [`AsSocket::as_socket`] + /// for an API which strictly borrows a socket. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_socket(&self) -> RawSocket; } @@ -138,16 +173,25 @@ pub trait AsRawSocket { /// Creates I/O objects from raw sockets. #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawSocket { - /// Creates a new I/O object from the given raw socket. + /// Constructs a new I/O object from the specified raw socket. + /// + /// This function is typically used to **consume ownership** of the socket + /// given, passing responsibility for closing the socket to the returned + /// object. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. /// - /// This function will **consume ownership** of the socket provided and - /// it will be closed when the returned object goes out of scope. + /// However, consuming ownership is not strictly required. Use a + /// `From<OwnedSocket>::from` implementation for an API which strictly + /// consumes ownership. /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// # Safety + /// + /// The `socket` passed in must: + /// - be a valid an open socket, + /// - be a socket that may be freed via [`closesocket`]. + /// + /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_socket(sock: RawSocket) -> Self; } @@ -158,9 +202,13 @@ pub trait FromRawSocket { pub trait IntoRawSocket { /// Consumes this object, returning the raw underlying socket. /// - /// This function **transfers ownership** of the underlying socket to the - /// caller. Callers are then the unique owners of the socket and must close - /// it once it's no longer needed. + /// This function is typically used to **transfer ownership** of the underlying + /// socket to the caller. When used in this way, callers are then the unique + /// owners of the socket and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// `Into<OwnedSocket>::into` implementation for an API which strictly + /// transfers ownership. #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_socket(self) -> RawSocket; } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 2f13eb77a1b..a6b979cc22b 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -21,6 +21,10 @@ use crate::sys::cvt; /// so it can be used in FFI in places where a socket is passed as an argument, /// it is not captured or consumed, and it never has the value /// `INVALID_SOCKET`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedSocket` +/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw +/// socket, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -67,7 +71,7 @@ impl BorrowedSocket<'_> { /// `INVALID_SOCKET`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_socket(socket: RawSocket) -> Self { + pub unsafe fn borrow_raw(socket: RawSocket) -> Self { debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); Self { socket, _phantom: PhantomData } } @@ -168,13 +172,6 @@ impl IntoRawSocket for OwnedSocket { } impl FromRawSocket for OwnedSocket { - /// Constructs a new instance of `Self` from the given raw socket. - /// - /// # Safety - /// - /// The resource pointed to by `socket` must be open and suitable for - /// assuming ownership. The resource must not require cleanup other than - /// `closesocket`. #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); @@ -239,14 +236,14 @@ impl AsSocket for OwnedSocket { // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity // invariants, and the `BorrowdSocket` is bounded by the lifetime // of `&self`. - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } impl AsSocket for crate::net::TcpStream { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } @@ -267,7 +264,7 @@ impl From<OwnedSocket> for crate::net::TcpStream { impl AsSocket for crate::net::TcpListener { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } @@ -288,7 +285,7 @@ impl From<OwnedSocket> for crate::net::TcpListener { impl AsSocket for crate::net::UdpSocket { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index b268ef5c364..0b6cdb923bd 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -384,11 +384,8 @@ pub fn current_exe() -> io::Result<PathBuf> { if let Ok(path) = crate::fs::read_link("/proc/self/path/a.out") { Ok(path) } else { - extern "C" { - fn getexecname() -> *const c_char; - } unsafe { - let path = getexecname(); + let path = libc::getexecname(); if path.is_null() { Err(io::Error::last_os_error()) } else { diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 9fc2d9fce4d..07a0339c066 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -3,11 +3,11 @@ use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; -use crate::os::raw::NonZero_c_int; use crate::ptr; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; +use core::ffi::NonZero_c_int; #[cfg(target_os = "linux")] use crate::os::linux::process::PidFd; diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index 7d549d060fd..bbabdf787d9 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -3,12 +3,12 @@ use crate::fmt; use crate::io; use crate::io::ErrorKind; use crate::num::NonZeroI32; -use crate::os::raw::NonZero_c_int; use crate::sys; use crate::sys::cvt; use crate::sys::pipe::AnonPipe; use crate::sys::process::process_common::*; use crate::sys::unix::unsupported::*; +use core::ffi::NonZero_c_int; use libc::{c_int, pid_t}; diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index c6714d3aae2..56ed6cfeb6a 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -2,11 +2,11 @@ use crate::convert::{TryFrom, TryInto}; use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::num::NonZeroI32; -use crate::os::raw::NonZero_c_int; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; use crate::sys_common::thread; +use core::ffi::NonZero_c_int; use libc::RTP_ID; use libc::{self, c_char, c_int}; diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index b359987595d..e4d83ba0ffd 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -96,7 +96,7 @@ pub fn panic_output() -> Option<impl io::Write> { impl AsFd for io::Stdin { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) } } } @@ -104,7 +104,7 @@ impl AsFd for io::Stdin { impl<'a> AsFd for io::StdinLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) } } } @@ -112,7 +112,7 @@ impl<'a> AsFd for io::StdinLock<'a> { impl AsFd for io::Stdout { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) } } } @@ -120,7 +120,7 @@ impl AsFd for io::Stdout { impl<'a> AsFd for io::StdoutLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) } } } @@ -128,7 +128,7 @@ impl<'a> AsFd for io::StdoutLock<'a> { impl AsFd for io::Stderr { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) } } } @@ -136,6 +136,6 @@ impl AsFd for io::Stderr { impl<'a> AsFd for io::StderrLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) } } } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index cf8cf5ad49f..ff01ce27333 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -279,10 +279,15 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { ))] { #[cfg(any(target_os = "android", target_os = "linux"))] { + let quota = cgroup2_quota().max(1); let mut set: libc::cpu_set_t = unsafe { mem::zeroed() }; - if unsafe { libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) } == 0 { - let count = unsafe { libc::CPU_COUNT(&set) }; - return Ok(unsafe { NonZeroUsize::new_unchecked(count as usize) }); + unsafe { + if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 { + let count = libc::CPU_COUNT(&set) as usize; + let count = count.min(quota); + // SAFETY: affinity mask can't be empty and the quota gets clamped to a minimum of 1 + return Ok(NonZeroUsize::new_unchecked(count)); + } } } match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { @@ -368,6 +373,80 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { } } +/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot +/// be determined or is not set. +#[cfg(any(target_os = "android", target_os = "linux"))] +fn cgroup2_quota() -> usize { + use crate::ffi::OsString; + use crate::fs::{try_exists, File}; + use crate::io::Read; + use crate::os::unix::ffi::OsStringExt; + use crate::path::PathBuf; + + let mut quota = usize::MAX; + + let _: Option<()> = try { + let mut buf = Vec::with_capacity(128); + // find our place in the cgroup hierarchy + File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?; + let cgroup_path = buf + .split(|&c| c == b'\n') + .filter_map(|line| { + let mut fields = line.splitn(3, |&c| c == b':'); + // expect cgroupv2 which has an empty 2nd field + if fields.nth(1) != Some(b"") { + return None; + } + let path = fields.last()?; + // skip leading slash + Some(path[1..].to_owned()) + }) + .next()?; + let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path)); + + let mut path = PathBuf::with_capacity(128); + let mut read_buf = String::with_capacity(20); + + let cgroup_mount = "/sys/fs/cgroup"; + + path.push(cgroup_mount); + path.push(&cgroup_path); + + path.push("cgroup.controllers"); + + // skip if we're not looking at cgroup2 + if matches!(try_exists(&path), Err(_) | Ok(false)) { + return usize::MAX; + }; + + path.pop(); + + while path.starts_with(cgroup_mount) { + path.push("cpu.max"); + + read_buf.clear(); + + if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() { + let raw_quota = read_buf.lines().next()?; + let mut raw_quota = raw_quota.split(' '); + let limit = raw_quota.next()?; + let period = raw_quota.next()?; + match (limit.parse::<usize>(), period.parse::<usize>()) { + (Ok(limit), Ok(period)) => { + quota = quota.min(limit / period); + } + _ => {} + } + } + + path.pop(); // pop filename + path.pop(); // pop dir + } + }; + + quota +} + #[cfg(all( not(target_os = "linux"), not(target_os = "freebsd"), diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index c7b6290693e..2affd7e75b0 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -5,9 +5,9 @@ #![unstable(issue = "none", feature = "windows_c")] use crate::mem; -use crate::os::raw::NonZero_c_ulong; use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; use crate::ptr; +use core::ffi::NonZero_c_ulong; use libc::{c_void, size_t, wchar_t}; diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index aa6400aeefa..5de12313784 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -407,11 +407,11 @@ impl Socket { } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE) + net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } pub fn nodelay(&self) -> io::Result<bool> { - let raw: c::BYTE = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; + let raw: c::BOOL = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; Ok(raw != 0) } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 70b29d4a92e..3b7cdd55a08 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -58,21 +58,36 @@ cfg_if::cfg_if! { // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// -pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { +pub fn setsockopt<T>( + sock: &Socket, + level: c_int, + option_name: c_int, + option_value: T, +) -> io::Result<()> { unsafe { - let payload = &payload as *const T as *const c_void; - cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::<T>() as c::socklen_t))?; + cvt(c::setsockopt( + sock.as_raw(), + level, + option_name, + &option_value as *const T as *const _, + mem::size_of::<T>() as c::socklen_t, + ))?; Ok(()) } } -pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<T> { +pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> { unsafe { - let mut slot: T = mem::zeroed(); - let mut len = mem::size_of::<T>() as c::socklen_t; - cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; - assert_eq!(len as usize, mem::size_of::<T>()); - Ok(slot) + let mut option_value: T = mem::zeroed(); + let mut option_len = mem::size_of::<T>() as c::socklen_t; + cvt(c::getsockopt( + sock.as_raw(), + level, + option_name, + &mut option_value as *mut T as *mut _, + &mut option_len, + ))?; + Ok(option_value) } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1be3ed757ba..2464a0e2e47 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -177,7 +177,7 @@ macro_rules! thread_local { macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ - #[cfg_attr(not(windows), inline)] // see comments below + #[cfg_attr(not(windows), inline(always))] // see comments below unsafe fn __getit() -> $crate::option::Option<&'static $t> { const INIT_EXPR: $t = $init; @@ -297,7 +297,7 @@ macro_rules! __thread_local_inner { // gets the pessimistic path for now where it's never inlined. // // The issue of "should enable on Windows sometimes" is #84933 - #[cfg_attr(not(windows), inline)] + #[cfg_attr(not(windows), inline(always))] unsafe fn __getit() -> $crate::option::Option<&'static $t> { #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f8d790c3785..09d1e714ab6 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1482,7 +1482,7 @@ fn _assert_sync_and_send() { /// /// Parallelism is a resource. A given machine provides a certain capacity for /// parallelism, i.e., a bound on the number of computations it can perform -/// simultaneously. This number often corresponds to the amount of CPUs or +/// simultaneously. This number often corresponds to the amount of CPUs a /// computer has, but it may diverge in various cases. /// /// Host environments such as VMs or container orchestrators may want to @@ -1524,7 +1524,10 @@ fn _assert_sync_and_send() { /// /// On Linux: /// - It may overcount the amount of parallelism available when limited by a -/// process-wide affinity mask, or when affected by cgroup limits. +/// process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be +/// queried, e.g. due to sandboxing. +/// - It may undercount the amount of parallelism if the current thread's affinity mask +/// does not reflect the process' cpuset, e.g. due to pinned threads. /// /// On all targets: /// - It may overcount the amount of parallelism available when running in a VM |
