diff options
Diffstat (limited to 'library/std/src')
41 files changed, 766 insertions, 316 deletions
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 5804701892e..1fc1d39b181 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -38,8 +38,8 @@ use super::map::{map_try_reserve_error, RandomState}; /// determined by the [`Eq`] trait, changes while it is in the set. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or /// unsafe code. The behavior resulting from such a logic error is not -/// specified, but will not result in undefined behavior. This could include -/// panics, incorrect results, aborts, memory leaks, and non-termination. +/// specified (it could include panics, incorrect results, aborts, memory +/// leaks, or non-termination) but will not be undefined behavior. /// /// # Examples /// @@ -1320,6 +1320,8 @@ where /// /// let mut intersection = a.intersection(&b); /// ``` +#[must_use = "this returns the intersection as an iterator, \ + without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1345,6 +1347,8 @@ pub struct Intersection<'a, T: 'a, S: 'a> { /// /// let mut difference = a.difference(&b); /// ``` +#[must_use = "this returns the difference as an iterator, \ + without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1370,6 +1374,8 @@ pub struct Difference<'a, T: 'a, S: 'a> { /// /// let mut intersection = a.symmetric_difference(&b); /// ``` +#[must_use = "this returns the difference as an iterator, \ + without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>, @@ -1392,6 +1398,8 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { /// /// let mut union_iter = a.union(&b); /// ``` +#[must_use = "this returns the union as an iterator, \ + without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { iter: Chain<Iter<'a, T>, Difference<'a, T, S>>, diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 0b392897f9d..d23f5244d88 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -878,40 +878,4 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Linear interpolation between `start` and `end`. - /// - /// This enables linear interpolation between `start` and `end`, where start is represented by - /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all - /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0 - /// at a given rate, the result will change from `start` to `end` at a similar rate. - /// - /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the - /// range from `start` to `end`. This also is useful for transition functions which might - /// move slightly past the end or start for a desired effect. Mathematically, the values - /// returned are equivalent to `start + self * (end - start)`, although we make a few specific - /// guarantees that are useful specifically to linear interpolation. - /// - /// These guarantees are: - /// - /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the - /// value at 1.0 is always `end`. (exactness) - /// * If `start` and `end` are [finite], the values will always move in the direction from - /// `start` to `end` (monotonicity) - /// * If `self` is [finite] and `start == end`, the value at any point will always be - /// `start == end`. (consistency) - /// - /// [finite]: #method.is_finite - #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "float_interpolation", issue = "86269")] - pub fn lerp(self, start: f32, end: f32) -> f32 { - // consistent - if start == end { - start - - // exact/monotonic - } else { - self.mul_add(end, (-self).mul_add(start, start)) - } - } } diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index fe66a73afd6..0d4b865f339 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -757,66 +757,3 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } - -#[test] -fn test_lerp_exact() { - // simple values - assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0); - assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0); - - // boundary values - assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN); - assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX); -} - -#[test] -fn test_lerp_consistent() { - assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN); - assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX); - - // as long as t is finite, a/b can be infinite - assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY); - assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY); -} - -#[test] -fn test_lerp_nan_infinite() { - // non-finite t is not NaN if a/b different - assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan()); - assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan()); -} - -#[test] -fn test_lerp_values() { - // just a few basic values - assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25); - assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50); - assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75); -} - -#[test] -fn test_lerp_monotonic() { - // near 0 - let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX); - let zero = f32::lerp(0.0, f32::MIN, f32::MAX); - let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX); - assert!(below_zero <= zero); - assert!(zero <= above_zero); - assert!(below_zero <= above_zero); - - // near 0.5 - let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX); - let half = f32::lerp(0.5, f32::MIN, f32::MAX); - let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX); - assert!(below_half <= half); - assert!(half <= above_half); - assert!(below_half <= above_half); - - // near 1 - let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX); - let one = f32::lerp(1.0, f32::MIN, f32::MAX); - let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX); - assert!(below_one <= one); - assert!(one <= above_one); - assert!(below_one <= above_one); -} diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 602cceb5d1a..55e17b47190 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -881,42 +881,6 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - /// Linear interpolation between `start` and `end`. - /// - /// This enables linear interpolation between `start` and `end`, where start is represented by - /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all - /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0 - /// at a given rate, the result will change from `start` to `end` at a similar rate. - /// - /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the - /// range from `start` to `end`. This also is useful for transition functions which might - /// move slightly past the end or start for a desired effect. Mathematically, the values - /// returned are equivalent to `start + self * (end - start)`, although we make a few specific - /// guarantees that are useful specifically to linear interpolation. - /// - /// These guarantees are: - /// - /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the - /// value at 1.0 is always `end`. (exactness) - /// * If `start` and `end` are [finite], the values will always move in the direction from - /// `start` to `end` (monotonicity) - /// * If `self` is [finite] and `start == end`, the value at any point will always be - /// `start == end`. (consistency) - /// - /// [finite]: #method.is_finite - #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "float_interpolation", issue = "86269")] - pub fn lerp(self, start: f64, end: f64) -> f64 { - // consistent - if start == end { - start - - // exact/monotonic - } else { - self.mul_add(end, (-self).mul_add(start, start)) - } - } - // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 04cb0109261..5c163cfe90e 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -753,58 +753,3 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } - -#[test] -fn test_lerp_exact() { - // simple values - assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0); - assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0); - - // boundary values - assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN); - assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX); -} - -#[test] -fn test_lerp_consistent() { - assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN); - assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX); - - // as long as t is finite, a/b can be infinite - assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY); - assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY); -} - -#[test] -fn test_lerp_nan_infinite() { - // non-finite t is not NaN if a/b different - assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan()); - assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan()); -} - -#[test] -fn test_lerp_values() { - // just a few basic values - assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25); - assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50); - assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75); -} - -#[test] -fn test_lerp_monotonic() { - // near 0 - let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX); - let zero = f64::lerp(0.0, f64::MIN, f64::MAX); - let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX); - assert!(below_zero <= zero); - assert!(zero <= above_zero); - assert!(below_zero <= above_zero); - - // near 1 - let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX); - let one = f64::lerp(1.0, f64::MIN, f64::MAX); - let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX); - assert!(below_one <= one); - assert!(one <= above_one); - assert!(below_one <= above_one); -} diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 6827d3a8d24..b7822b40a7c 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -251,13 +251,12 @@ pub struct FromBytesWithNulError { /// # Examples /// /// ``` -/// #![feature(cstring_from_vec_with_nul)] /// use std::ffi::{CString, FromVecWithNulError}; /// /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err(); /// ``` #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub struct FromVecWithNulError { error_kind: FromBytesWithNulErrorKind, bytes: Vec<u8>, @@ -278,7 +277,7 @@ impl FromBytesWithNulError { } } -#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl FromVecWithNulError { /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`]. /// @@ -287,7 +286,6 @@ impl FromVecWithNulError { /// Basic usage: /// /// ``` - /// #![feature(cstring_from_vec_with_nul)] /// use std::ffi::CString; /// /// // Some invalid bytes in a vector @@ -298,6 +296,7 @@ impl FromVecWithNulError { /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes()); /// ``` #[must_use] + #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] } @@ -313,7 +312,6 @@ impl FromVecWithNulError { /// Basic usage: /// /// ``` - /// #![feature(cstring_from_vec_with_nul)] /// use std::ffi::CString; /// /// // Some invalid bytes in a vector @@ -324,6 +322,7 @@ impl FromVecWithNulError { /// assert_eq!(bytes, value.unwrap_err().into_bytes()); /// ``` #[must_use = "`self` will be dropped if the result is not used"] + #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub fn into_bytes(self) -> Vec<u8> { self.bytes } @@ -704,7 +703,6 @@ impl CString { /// # Example /// /// ``` - /// #![feature(cstring_from_vec_with_nul)] /// use std::ffi::CString; /// assert_eq!( /// unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) }, @@ -712,7 +710,7 @@ impl CString { /// ); /// ``` #[must_use] - #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] + #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self { Self { inner: v.into_boxed_slice() } } @@ -733,7 +731,6 @@ impl CString { /// when called without the ending nul byte. /// /// ``` - /// #![feature(cstring_from_vec_with_nul)] /// use std::ffi::CString; /// assert_eq!( /// CString::from_vec_with_nul(b"abc\0".to_vec()) @@ -745,14 +742,13 @@ impl CString { /// An incorrectly formatted [`Vec`] will produce an error. /// /// ``` - /// #![feature(cstring_from_vec_with_nul)] /// use std::ffi::{CString, FromVecWithNulError}; /// // Interior nul byte /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err(); /// // No nul byte /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err(); /// ``` - #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] + #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> { let nul_pos = memchr::memchr(0, &v); match nul_pos { @@ -1084,10 +1080,10 @@ impl fmt::Display for FromBytesWithNulError { } } -#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl Error for FromVecWithNulError {} -#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl fmt::Display for FromVecWithNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.error_kind { @@ -1175,6 +1171,7 @@ impl CStr { /// } /// # } /// ``` + #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { @@ -1260,7 +1257,7 @@ impl CStr { #[inline] #[must_use] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")] + #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { // SAFETY: Casting to CStr is safe because its internal representation // is a [u8] too (safe only inside std). diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 82a76aa73c5..7f3bb836754 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -145,7 +145,7 @@ #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub use self::c_str::FromBytesWithNulError; -#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub use self::c_str::FromVecWithNulError; #[stable(feature = "rust1", since = "1.0.0")] pub use self::c_str::{CStr, CString, IntoStringError, NulError}; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 46c9aa5e627..49e268eb99b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -829,6 +829,7 @@ impl OsStr { /// assert!(!non_ascii.is_ascii()); /// ``` #[stable(feature = "osstring_ascii", since = "1.53.0")] + #[must_use] #[inline] pub fn is_ascii(&self) -> bool { self.inner.is_ascii() diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 9f45e89aa75..2b76a411a0f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1046,7 +1046,6 @@ impl Metadata { /// #[cfg_attr(unix, doc = "```no_run")] #[cfg_attr(not(unix), doc = "```ignore")] - /// #![feature(is_symlink)] /// use std::fs; /// use std::path::Path; /// use std::os::unix::fs::symlink; @@ -1062,7 +1061,7 @@ impl Metadata { /// } /// ``` #[must_use] - #[unstable(feature = "is_symlink", issue = "85748")] + #[stable(feature = "is_symlink", since = "1.57.0")] pub fn is_symlink(&self) -> bool { self.file_type().is_symlink() } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 13dbae3b7b5..628de13156c 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1411,3 +1411,32 @@ fn symlink_hard_link() { // "hard_link" should still appear as a symlink. assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink()); } + +/// Ensure `fs::create_dir` works on Windows with longer paths. +#[test] +#[cfg(windows)] +fn create_dir_long_paths() { + use crate::{ffi::OsStr, iter, os::windows::ffi::OsStrExt}; + const PATH_LEN: usize = 247; + + let tmpdir = tmpdir(); + let mut path = tmpdir.path().to_path_buf(); + path.push("a"); + let mut path = path.into_os_string(); + + let utf16_len = path.encode_wide().count(); + if utf16_len >= PATH_LEN { + // Skip the test in the unlikely event the local user has a long temp directory path. + // This should not affect CI. + return; + } + // Increase the length of the path. + path.extend(iter::repeat(OsStr::new("a")).take(PATH_LEN - utf16_len)); + + // This should succeed. + fs::create_dir(&path).unwrap(); + + // This will fail if the path isn't converted to verbatim. + path.push("a"); + fs::create_dir(&path).unwrap(); +} diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 9389501e012..96a9da24c7e 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -487,6 +487,7 @@ impl Stdin { /// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap())); /// } /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "stdin_forwarders", issue = "87096")] pub fn split(self, byte: u8) -> Split<StdinLock<'static>> { self.into_locked().split(byte) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1d2d26b8f00..c2243b25953 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -257,6 +257,7 @@ #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] +#![feature(const_fn_trait_bound)] #![feature(const_format_args)] #![feature(const_io_structs)] #![feature(const_ip)] @@ -272,7 +273,7 @@ #![feature(custom_test_frameworks)] #![feature(decl_macro)] #![feature(doc_cfg)] -#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] +#![feature(doc_cfg_hide)] #![feature(doc_keyword)] #![feature(doc_masked)] #![feature(doc_notable_trait)] @@ -284,7 +285,6 @@ #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] #![feature(extend_one)] -#![feature(float_interpolation)] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] @@ -308,7 +308,7 @@ #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] #![feature(mixed_integer_ops)] -#![cfg_attr(not(bootstrap), feature(must_not_suspend))] +#![feature(must_not_suspend)] #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] @@ -324,7 +324,6 @@ #![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(rustc_private)] -#![feature(saturating_div)] #![feature(saturating_int_impl)] #![feature(slice_concat_ext)] #![feature(slice_internals)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index e5e9fedb61e..c080f783cbb 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -59,7 +59,8 @@ pub enum IpAddr { /// /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal /// notation, divided by `.` (this is called "dot-decimal notation"). -/// Notably, octal numbers and hexadecimal numbers are not allowed per [IETF RFC 6943]. +/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which +/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. /// /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 /// [`FromStr`]: crate::str::FromStr @@ -72,6 +73,9 @@ pub enum IpAddr { /// let localhost = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); +/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal +/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal +/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex /// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index babc854cd1d..17581f33026 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -20,6 +20,14 @@ fn test_from_str_ipv4() { // no number between dots let none: Option<Ipv4Addr> = "255.0..1".parse().ok(); assert_eq!(None, none); + // octal + let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok(); + assert_eq!(None, none); + // octal zero + let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok(); + assert_eq!(None, none); + let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok(); + assert_eq!(None, none); } #[test] diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index 88a8cb76bef..4e16a55edec 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -111,10 +111,12 @@ impl<'a> Parser<'a> { &mut self, radix: u32, max_digits: Option<usize>, + allow_zero_prefix: bool, ) -> Option<T> { self.read_atomically(move |p| { let mut result = T::ZERO; let mut digit_count = 0; + let has_leading_zero = p.peek_char() == Some('0'); while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { result = result.checked_mul(radix)?; @@ -127,7 +129,13 @@ impl<'a> Parser<'a> { } } - if digit_count == 0 { None } else { Some(result) } + if digit_count == 0 { + None + } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { + None + } else { + Some(result) + } }) } @@ -140,10 +148,7 @@ impl<'a> Parser<'a> { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 - match (p.peek_char(), p.read_number(10, None)) { - (Some('0'), Some(number)) if number != 0 => None, - (_, number) => number, - } + p.read_number(10, Some(3), false) })?; } @@ -175,7 +180,7 @@ impl<'a> Parser<'a> { } } - let group = p.read_separator(':', i, |p| p.read_number(16, Some(4))); + let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true)); match group { Some(g) => *slot = g, @@ -227,7 +232,7 @@ impl<'a> Parser<'a> { fn read_port(&mut self) -> Option<u16> { self.read_atomically(|p| { p.read_given_char(':')?; - p.read_number(10, None) + p.read_number(10, None, true) }) } @@ -235,7 +240,7 @@ impl<'a> Parser<'a> { fn read_scope_id(&mut self) -> Option<u32> { self.read_atomically(|p| { p.read_given_char('%')?; - p.read_number(10, None) + p.read_number(10, None, true) }) } @@ -281,7 +286,12 @@ impl FromStr for IpAddr { impl FromStr for Ipv4Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> { - Parser::new(s).parse_with(|p| p.read_ipv4_addr()) + // don't try to parse if too long + if s.len() > 15 { + Err(AddrParseError(())) + } else { + Parser::new(s).parse_with(|p| p.read_ipv4_addr()) + } } } diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index c9ccc26f4e1..887f6059939 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -92,8 +92,8 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { #[derive(Clone)] #[stable(feature = "unix_socket", since = "1.10.0")] pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, + pub(super) addr: libc::sockaddr_un, + pub(super) len: libc::socklen_t, } impl SocketAddr { @@ -198,6 +198,31 @@ impl SocketAddr { if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } } + /// Returns the contents of this address if it is an abstract namespace + /// without the leading null byte. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let namespace = b"hidden"; + /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?; + /// let socket = UnixListener::bind_addr(&namespace_addr)?; + /// let local_addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..])); + /// Ok(()) + /// } + /// ``` + #[doc(cfg(any(target_os = "android", target_os = "linux")))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn as_abstract_namespace(&self) -> Option<&[u8]> { + if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } + } + fn address(&self) -> AddressKind<'_> { let len = self.len as usize - sun_path_offset(&self.addr); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; @@ -214,6 +239,65 @@ impl SocketAddr { AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) } } + + /// Creates an abstract domain socket address from a namespace + /// + /// An abstract address does not create a file unlike traditional path-based + /// Unix sockets. The advantage of this is that the address will disappear when + /// the socket bound to it is closed, so no filesystem clean up is required. + /// + /// The leading null byte for the abstract namespace is automatically added. + /// + /// This is a Linux-specific extension. See more at [`unix(7)`]. + /// + /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html + /// + /// # Errors + /// + /// This will return an error if the given namespace is too long + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; + /// let listener = match UnixListener::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[doc(cfg(any(target_os = "android", target_os = "linux")))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + if namespace.len() + 1 > addr.sun_path.len() { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"namespace must be shorter than SUN_LEN", + )); + } + + crate::ptr::copy_nonoverlapping( + namespace.as_ptr(), + addr.sun_path.as_mut_ptr().offset(1) as *mut u8, + namespace.len(), + ); + let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; + SocketAddr::from_parts(addr, len) + } + } } #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index f11eec18cc5..a2caccc7849 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -112,6 +112,41 @@ impl UnixDatagram { } } + /// Creates a Unix datagram socket bound to an address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram}; + /// + /// fn main() -> std::io::Result<()> { + /// let sock1 = UnixDatagram::bind("path/to/socket")?; + /// let addr = sock1.local_addr()?; + /// + /// let sock2 = match UnixDatagram::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> { + unsafe { + let socket = UnixDatagram::unbound()?; + cvt(libc::bind( + socket.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len as _, + ))?; + Ok(socket) + } + } + /// Creates a Unix Datagram socket which is not bound to any address. /// /// # Examples @@ -156,7 +191,7 @@ impl UnixDatagram { Ok((UnixDatagram(i1), UnixDatagram(i2))) } - /// Connects the socket to the specified address. + /// Connects the socket to the specified path address. /// /// The [`send`] method may be used to send data to the specified address. /// [`recv`] and [`recv_from`] will only receive data from that address. @@ -192,6 +227,41 @@ impl UnixDatagram { Ok(()) } + /// Connects the socket to an address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram}; + /// + /// fn main() -> std::io::Result<()> { + /// let bound = UnixDatagram::bind("/path/to/socket")?; + /// let addr = bound.local_addr()?; + /// + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect_addr(&addr) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { + unsafe { + cvt(libc::connect( + self.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + } + Ok(()) + } + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `UnixDatagram` is a reference to the same socket that this @@ -473,6 +543,42 @@ impl UnixDatagram { } } + /// Sends data on the socket to the specified [SocketAddr]. + /// + /// On success, returns the number of bytes written. + /// + /// [SocketAddr]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram}; + /// + /// fn main() -> std::io::Result<()> { + /// let bound = UnixDatagram::bind("/path/to/socket")?; + /// let addr = bound.local_addr()?; + /// + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> { + unsafe { + let count = cvt(libc::sendto( + self.as_raw_fd(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + Ok(count as usize) + } + } + /// Sends data on the socket to the socket's peer. /// /// The peer address may be set by the `connect` method, and this method diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index f08bd252e46..97348afe7de 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -81,6 +81,44 @@ impl UnixListener { } } + /// Creates a new `UnixListener` bound to the specified [`socket address`]. + /// + /// [`socket address`]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener}; + /// + /// fn main() -> std::io::Result<()> { + /// let listener1 = UnixListener::bind("path/to/socket")?; + /// let addr = listener1.local_addr()?; + /// + /// let listener2 = match UnixListener::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + cvt(libc::bind( + inner.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len as _, + ))?; + cvt(libc::listen(inner.as_raw_fd(), 128))?; + Ok(UnixListener(inner)) + } + } + /// Accepts a new incoming connection to this listener. /// /// This function will block the calling thread until a new Unix connection diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 4119de3c03c..6120d557227 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -106,6 +106,43 @@ impl UnixStream { } } + /// Connects to the socket specified by [`address`]. + /// + /// [`address`]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, UnixStream}; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr()?; + /// + /// let sock = match UnixStream::connect_addr(&addr) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ```` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + cvt(libc::connect( + inner.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + Ok(UnixStream(inner)) + } + } + /// Creates an unnamed pair of connected sockets. /// /// Returns two `UnixStream`s which are connected to each other. diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index bd9b6dd727b..7ad4a02611e 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -304,6 +304,30 @@ fn test_unnamed_unix_datagram() { } #[test] +fn test_unix_datagram_connect_to_recv_addr() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::bind(&path2)); + + let msg = b"hello world"; + let sock1_addr = or_panic!(sock1.local_addr()); + or_panic!(sock2.send_to_addr(msg, &sock1_addr)); + let mut buf = [0; 11]; + let (_, addr) = or_panic!(sock1.recv_from(&mut buf)); + + let new_msg = b"hello back"; + let mut new_buf = [0; 10]; + or_panic!(sock2.connect_addr(&addr)); + or_panic!(sock2.send(new_msg)); // set by connect_addr + let usize = or_panic!(sock2.recv(&mut new_buf)); + assert_eq!(usize, 10); + assert_eq!(new_msg, &new_buf[..]); +} + +#[test] fn test_connect_unix_datagram() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -388,10 +412,133 @@ fn test_unix_datagram_timeout_zero_duration() { } #[test] -fn abstract_namespace_not_allowed() { +fn abstract_namespace_not_allowed_connect() { assert!(UnixStream::connect("\0asdf").is_err()); } +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_stream_connect() { + let msg1 = b"hello"; + let msg2 = b"world"; + + let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace")); + let listener = or_panic!(UnixListener::bind_addr(&socket_addr)); + + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect_addr(&socket_addr)); + + let peer = or_panic!(stream.peer_addr()); + assert_eq!(peer.as_abstract_namespace().unwrap(), b"namespace"); + + or_panic!(stream.write_all(msg1)); + let mut buf = vec![]; + or_panic!(stream.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(stream); + + thread.join().unwrap(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_stream_iter() { + let addr = or_panic!(SocketAddr::from_abstract_namespace(b"hidden")); + let listener = or_panic!(UnixListener::bind_addr(&addr)); + + let thread = thread::spawn(move || { + for stream in listener.incoming().take(2) { + let mut stream = or_panic!(stream); + let mut buf = [0]; + or_panic!(stream.read(&mut buf)); + } + }); + + for _ in 0..2 { + let mut stream = or_panic!(UnixStream::connect_addr(&addr)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_datagram_bind_send_to_addr() { + let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns1")); + let sock1 = or_panic!(UnixDatagram::bind_addr(&addr1)); + + let local = or_panic!(sock1.local_addr()); + assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1"); + + let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2")); + let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2)); + + let msg = b"hello world"; + or_panic!(sock1.send_to_addr(msg, &addr2)); + let mut buf = [0; 11]; + let (len, addr) = or_panic!(sock2.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); + assert_eq!(len, 11); + assert_eq!(addr.as_abstract_namespace().unwrap(), b"ns1"); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_datagram_connect_addr() { + let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns3")); + let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1)); + + let sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect_addr(&addr1)); + + let msg = b"hello world"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (len, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(len, 11); + assert_eq!(addr.is_unnamed(), true); + assert_eq!(msg, &buf[..]); + + let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4")); + let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2)); + + or_panic!(sock.connect_addr(&addr2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_namespace_too_long() { + match SocketAddr::from_abstract_namespace( + b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\ + opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\ + jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + ) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_namespace_no_pathname_and_not_unnamed() { + let namespace = b"local"; + let addr = or_panic!(SocketAddr::from_abstract_namespace(&namespace[..])); + assert_eq!(addr.as_pathname(), None); + assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..])); + assert_eq!(addr.is_unnamed(), false); +} + #[test] fn test_unix_stream_peek() { let (txdone, rxdone) = crate::sync::mpsc::channel(); diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 4d23805e479..9b94615d247 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -239,27 +239,27 @@ pub trait ExitStatusExt: Sealed { fn signal(&self) -> Option<i32>; /// If the process was terminated by a signal, says whether it dumped core. - #[unstable(feature = "unix_process_wait_more", issue = "80695")] + #[stable(feature = "unix_process_wait_more", since = "1.58.0")] fn core_dumped(&self) -> bool; /// If the process was stopped by a signal, returns that signal. /// /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`. - #[unstable(feature = "unix_process_wait_more", issue = "80695")] + #[stable(feature = "unix_process_wait_more", since = "1.58.0")] fn stopped_signal(&self) -> Option<i32>; /// Whether the process was continued from a stopped status. /// /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`. - #[unstable(feature = "unix_process_wait_more", issue = "80695")] + #[stable(feature = "unix_process_wait_more", since = "1.58.0")] fn continued(&self) -> bool; /// Returns the underlying raw `wait` status. /// /// The returned integer is a **wait status, not an exit status**. - #[unstable(feature = "unix_process_wait_more", issue = "80695")] + #[stable(feature = "unix_process_wait_more", since = "1.58.0")] fn into_raw(self) -> i32; } diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 21e9669c110..c0605b2f412 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -25,7 +25,7 @@ pub macro panic_2015 { $crate::rt::panic_display(&$arg) }), ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+)) + $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) }), } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 231c9fc19c0..437fcbb3176 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -437,31 +437,9 @@ pub fn panicking() -> bool { !panic_count::count_is_zero() } -/// The entry point for panicking with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] -#[cold] -// If panic_immediate_abort, inline the abort call, -// otherwise avoid inlining because of it is cold path. -#[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cfg_attr(not(test), lang = "begin_panic_fmt")] -pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { - if cfg!(feature = "panic_immediate_abort") { - intrinsics::abort() - } - - let info = PanicInfo::internal_constructor(Some(msg), Location::caller()); - begin_panic_handler(&info) -} - /// Entry point of panics from the libcore crate (`panic_impl` lang item). -#[cfg_attr(not(test), panic_handler)] +#[cfg(not(test))] +#[panic_handler] pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { struct PanicPayload<'a> { inner: &'a fmt::Arguments<'a>, @@ -534,7 +512,8 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cold] #[track_caller] -pub fn begin_panic<M: Any + Send>(msg: M) -> ! { +#[rustc_do_not_const_check] // hooked by const-eval +pub const fn begin_panic<M: Any + Send>(msg: M) -> ! { if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 47156dc33e5..4e547a80258 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1208,6 +1208,9 @@ impl PathBuf { /// * if `path` has a root but no prefix (e.g., `\windows`), it /// replaces everything except for the prefix (if any) of `self`. /// * if `path` has a prefix but no root, it replaces `self`. + /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`) + /// and `path` is not empty, the new path is normalized: all references + /// to `.` and `..` are removed. /// /// # Examples /// @@ -1254,7 +1257,7 @@ impl PathBuf { self.as_mut_vec().truncate(0); // verbatim paths need . and .. removed - } else if comps.prefix_verbatim() { + } else if comps.prefix_verbatim() && !path.inner.is_empty() { let mut buf: Vec<_> = comps.collect(); for c in path.components() { match c { @@ -2748,7 +2751,7 @@ impl Path { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } - /// Returns true if the path exists on disk and is pointing at a symbolic link. + /// Returns `true` if the path exists on disk and is pointing at a symbolic link. /// /// This function will not traverse symbolic links. /// In case of a broken symbolic link this will also return true. @@ -2760,7 +2763,6 @@ impl Path { /// #[cfg_attr(unix, doc = "```no_run")] #[cfg_attr(not(unix), doc = "```ignore")] - /// #![feature(is_symlink)] /// use std::path::Path; /// use std::os::unix::fs::symlink; /// @@ -2769,8 +2771,14 @@ impl Path { /// assert_eq!(link_path.is_symlink(), true); /// assert_eq!(link_path.exists(), false); /// ``` - #[unstable(feature = "is_symlink", issue = "85748")] + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call + /// [`fs::Metadata::is_symlink`] if it was [`Ok`]. #[must_use] + #[stable(feature = "is_symlink", since = "1.57.0")] pub fn is_symlink(&self) -> bool { fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false) } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 3973a6829d3..0a16ff2a721 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1271,6 +1271,7 @@ pub fn test_push() { tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo"); tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo"); tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo"); + tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\"); } } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 4d72aff0116..121c214780d 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -19,8 +19,8 @@ use crate::ffi::CString; // Re-export some of our utilities which are expected by other crates. -pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count}; -pub use core::panicking::panic_display; +pub use crate::panicking::{begin_panic, panic_count}; +pub use core::panicking::{panic_display, panic_fmt}; use crate::sync::Once; use crate::sys; diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 133c3e46cd8..11836b7b694 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -130,7 +130,7 @@ impl Barrier { if lock.count < self.num_threads { // We need a while loop to guard against spurious wakeups. // https://en.wikipedia.org/wiki/Spurious_wakeup - while local_gen == lock.generation_id && lock.count < self.num_threads { + while local_gen == lock.generation_id { lock = self.cvar.wait(lock).unwrap(); } BarrierWaitResult(false) diff --git a/library/std/src/sync/mpsc/cache_aligned.rs b/library/std/src/sync/mpsc/cache_aligned.rs index b0842144328..f95b0ddd589 100644 --- a/library/std/src/sync/mpsc/cache_aligned.rs +++ b/library/std/src/sync/mpsc/cache_aligned.rs @@ -2,10 +2,7 @@ use crate::ops::{Deref, DerefMut}; #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(align(64))] -pub(super) struct Aligner; - -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(super) struct CacheAligned<T>(pub T, pub Aligner); +pub(super) struct CacheAligned<T>(pub T); impl<T> Deref for CacheAligned<T> { type Target = T; @@ -22,6 +19,6 @@ impl<T> DerefMut for CacheAligned<T> { impl<T> CacheAligned<T> { pub(super) fn new(t: T) -> Self { - CacheAligned(t, Aligner) + CacheAligned(t) } } diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index fa8ef8fc37a..b62f21a9dac 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -55,8 +55,20 @@ impl Condvar { mutex.lock(); } - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - panic!("wait_timeout not supported on hermit"); + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + self.counter.fetch_add(1, SeqCst); + mutex.unlock(); + let millis = dur.as_millis().min(u32::MAX as u128) as u32; + + let res = if millis > 0 { + abi::sem_timedwait(self.sem1, millis) + } else { + abi::sem_trywait(self.sem1) + }; + + abi::sem_post(self.sem2); + mutex.lock(); + res == 0 } pub unsafe fn destroy(&self) { diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index 880ef678a4f..1a6b3bc63e6 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -182,7 +182,7 @@ impl TcpStream { Ok(self.clone()) } - pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> { + pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/unix/process/zircon.rs b/library/std/src/sys/unix/process/zircon.rs index 58427bb8b69..4dfa2b4ff1e 100644 --- a/library/std/src/sys/unix/process/zircon.rs +++ b/library/std/src/sys/unix/process/zircon.rs @@ -25,9 +25,12 @@ pub const ZX_TASK_TERMINATED: zx_signals_t = ZX_OBJECT_SIGNAL_3; pub const ZX_RIGHT_SAME_RIGHTS: zx_rights_t = 1 << 31; +// The upper four bits gives the minor version. pub type zx_object_info_topic_t = u32; -pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3; +pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3 | (1 << 28); + +pub type zx_info_process_flags_t = u32; pub fn zx_cvt<T>(t: T) -> io::Result<T> where @@ -68,9 +71,9 @@ impl Drop for Handle { #[repr(C)] pub struct zx_info_process_t { pub return_code: i64, - pub started: bool, - pub exited: bool, - pub debugger_attached: bool, + pub start_time: zx_time_t, + pub flags: zx_info_process_flags_t, + pub reserved1: u32, } extern "C" { diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 7dc09add27f..824283ef6c4 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -303,6 +303,7 @@ mod inner { pub fn actually_monotonic() -> bool { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) + || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64")) || cfg!(target_os = "fuchsia") } diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 6fb850d1828..9dfc8114eb5 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -262,6 +262,8 @@ pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; +pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -678,10 +680,6 @@ if #[cfg(not(target_vendor = "uwp"))] { #[link(name = "advapi32")] extern "system" { - // Forbidden when targeting UWP - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; - // Allowed but unused by UWP pub fn OpenProcessToken( ProcessHandle: HANDLE, @@ -743,8 +741,6 @@ if #[cfg(not(target_vendor = "uwp"))] { // UWP specific functions & types cfg_if::cfg_if! { if #[cfg(target_vendor = "uwp")] { - pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; - #[repr(C)] pub struct FILE_STANDARD_INFO { pub AllocationSize: LARGE_INTEGER, @@ -754,15 +750,6 @@ if #[cfg(target_vendor = "uwp")] { pub Directory: BOOLEAN, } - #[link(name = "bcrypt")] - extern "system" { - pub fn BCryptGenRandom( - hAlgorithm: LPVOID, - pBuffer: *mut u8, - cbBuffer: ULONG, - dwFlags: ULONG, - ) -> LONG; - } #[link(name = "kernel32")] extern "system" { pub fn GetFileInformationByHandleEx( @@ -990,6 +977,12 @@ extern "system" { cchCount2: c_int, bIgnoreCase: BOOL, ) -> c_int; + pub fn GetFullPathNameW( + lpFileName: LPCWSTR, + nBufferLength: DWORD, + lpBuffer: LPWSTR, + lpFilePart: *mut LPWSTR, + ) -> DWORD; } #[link(name = "ws2_32")] @@ -1085,6 +1078,18 @@ extern "system" { ) -> c_int; } +#[link(name = "bcrypt")] +extern "system" { + // >= Vista / Server 2008 + // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom + pub fn BCryptGenRandom( + hAlgorithm: LPVOID, + pBuffer: *mut u8, + cbBuffer: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; +} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn! { diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index ad550a823ae..9859000c8d4 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -14,6 +14,7 @@ use crate::sys::time::SystemTime; use crate::sys::{c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use super::path::maybe_verbatim; use super::to_u16s; pub struct File { @@ -281,7 +282,7 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { - let path = to_u16s(path)?; + let path = maybe_verbatim(path)?; let handle = unsafe { c::CreateFileW( path.as_ptr(), @@ -706,7 +707,7 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = to_u16s(p)?; + let p = maybe_verbatim(p)?; cvt(unsafe { c::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) })?; Ok(()) } @@ -715,7 +716,7 @@ impl DirBuilder { pub fn readdir(p: &Path) -> io::Result<ReadDir> { let root = p.to_path_buf(); let star = p.join("*"); - let path = to_u16s(&star)?; + let path = maybe_verbatim(&star)?; unsafe { let mut wfd = mem::zeroed(); @@ -733,20 +734,20 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> { } pub fn unlink(p: &Path) -> io::Result<()> { - let p_u16s = to_u16s(p)?; + let p_u16s = maybe_verbatim(p)?; cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?; Ok(()) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = to_u16s(old)?; - let new = to_u16s(new)?; + let old = maybe_verbatim(old)?; + let new = maybe_verbatim(new)?; cvt(unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) })?; Ok(()) } pub fn rmdir(p: &Path) -> io::Result<()> { - let p = to_u16s(p)?; + let p = maybe_verbatim(p)?; cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; Ok(()) } @@ -794,7 +795,7 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> { let original = to_u16s(original)?; - let link = to_u16s(link)?; + let link = maybe_verbatim(link)?; let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the @@ -823,8 +824,8 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> #[cfg(not(target_vendor = "uwp"))] pub fn link(original: &Path, link: &Path) -> io::Result<()> { - let original = to_u16s(original)?; - let link = to_u16s(link)?; + let original = maybe_verbatim(original)?; + let link = maybe_verbatim(link)?; cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?; Ok(()) } @@ -857,7 +858,7 @@ pub fn lstat(path: &Path) -> io::Result<FileAttr> { } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = to_u16s(p)?; + let p = maybe_verbatim(p)?; unsafe { cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; Ok(()) @@ -900,8 +901,8 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { } c::PROGRESS_CONTINUE } - let pfrom = to_u16s(from)?; - let pto = to_u16s(to)?; + let pfrom = maybe_verbatim(from)?; + let pto = maybe_verbatim(to)?; let mut size = 0i64; cvt(unsafe { c::CopyFileExW( diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 883690c4831..b5209aa690b 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -281,6 +281,10 @@ pub fn temp_dir() -> PathBuf { #[cfg(not(target_vendor = "uwp"))] fn home_dir_crt() -> Option<PathBuf> { unsafe { + // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below + // instead of us having to go through these multiple steps to get a token. However this is + // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7 + // we can simplify this code. See #90144 for details. use crate::sys::handle::Handle; let me = c::GetCurrentProcess(); diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index b8f512f6a23..460c1eff778 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -1,6 +1,10 @@ +use super::{c, fill_utf16_buf, to_u16s}; use crate::ffi::OsStr; +use crate::io; use crate::mem; +use crate::path::Path; use crate::path::Prefix; +use crate::ptr; #[cfg(test)] mod tests; @@ -141,3 +145,100 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { None => (path, OsStr::new("")), } } + +/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits. +/// +/// This path may or may not have a verbatim prefix. +pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> { + // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL). + // However, for APIs such as CreateDirectory[1], the limit is 248. + // + // [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters + const LEGACY_MAX_PATH: usize = 248; + // UTF-16 encoded code points, used in parsing and building UTF-16 paths. + // All of these are in the ASCII range so they can be cast directly to `u16`. + const SEP: u16 = b'\\' as _; + const ALT_SEP: u16 = b'/' as _; + const QUERY: u16 = b'?' as _; + const COLON: u16 = b':' as _; + const DOT: u16 = b'.' as _; + const U: u16 = b'U' as _; + const N: u16 = b'N' as _; + const C: u16 = b'C' as _; + + // \\?\ + const VERBATIM_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP]; + // \??\ + const NT_PREFIX: &[u16] = &[SEP, QUERY, QUERY, SEP]; + // \\?\UNC\ + const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP]; + + let mut path = to_u16s(path)?; + if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) { + // Early return for paths that are already verbatim. + return Ok(path); + } else if path.len() < LEGACY_MAX_PATH { + // Early return if an absolute path is less < 260 UTF-16 code units. + // This is an optimization to avoid calling `GetFullPathNameW` unnecessarily. + match path.as_slice() { + // Starts with `D:`, `D:\`, `D:/`, etc. + // Does not match if the path starts with a `\` or `/`. + [drive, COLON, 0] | [drive, COLON, SEP | ALT_SEP, ..] + if *drive != SEP && *drive != ALT_SEP => + { + return Ok(path); + } + // Starts with `\\`, `//`, etc + [SEP | ALT_SEP, SEP | ALT_SEP, ..] => return Ok(path), + _ => {} + } + } + + // Firstly, get the absolute path using `GetFullPathNameW`. + // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew + let lpfilename = path.as_ptr(); + fill_utf16_buf( + // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid. + // `lpfilename` is a pointer to a null terminated string that is not + // invalidated until after `GetFullPathNameW` returns successfully. + |buffer, size| unsafe { + // While the docs for `GetFullPathNameW` have the standard note + // about needing a `\\?\` path for a long lpfilename, this does not + // appear to be true in practice. + // See: + // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) + }, + |mut absolute| { + path.clear(); + + // Secondly, add the verbatim prefix. This is easier here because we know the + // path is now absolute and fully normalized (e.g. `/` has been changed to `\`). + let prefix = match absolute { + // C:\ => \\?\C:\ + [_, COLON, SEP, ..] => VERBATIM_PREFIX, + // \\.\ => \\?\ + [SEP, SEP, DOT, SEP, ..] => { + absolute = &absolute[4..]; + VERBATIM_PREFIX + } + // Leave \\?\ and \??\ as-is. + [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[], + // \\ => \\?\UNC\ + [SEP, SEP, ..] => { + absolute = &absolute[2..]; + UNC_PREFIX + } + // Anything else we leave alone. + _ => &[], + }; + + path.reserve_exact(prefix.len() + absolute.len() + 1); + path.extend_from_slice(prefix); + path.extend_from_slice(absolute); + path.push(0); + }, + )?; + Ok(path) +} diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index 9675da6ff88..c6c84519f41 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -42,3 +42,56 @@ fn test_parse_next_component() { (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share")) ); } + +#[test] +fn verbatim() { + use crate::path::Path; + fn check(path: &str, expected: &str) { + let verbatim = maybe_verbatim(Path::new(path)).unwrap(); + let verbatim = String::from_utf16_lossy(verbatim.strip_suffix(&[0]).unwrap()); + assert_eq!(&verbatim, expected, "{}", path); + } + + // Ensure long paths are correctly prefixed. + check( + r"C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + r"\\?\C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + ); + check( + r"\\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + r"\\?\UNC\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + ); + check( + r"\\.\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + r"\\?\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + ); + // `\\?\` prefixed paths are left unchanged... + check( + r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + ); + // But `//?/` is not a verbatim prefix so it will be normalized. + check( + r"//?/E:/verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + r"\\?\E:\verbatim\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt", + ); + + // For performance, short absolute paths are left unchanged. + check(r"C:\Program Files\Rust", r"C:\Program Files\Rust"); + check(r"\\server\share", r"\\server\share"); + check(r"\\.\COM1", r"\\.\COM1"); + + // Check that paths of length 247 are converted to verbatim. + // This is necessary for `CreateDirectory`. + check( + r"C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + r"\\?\C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ); + + // Make sure opening a drive will work. + check("Z:", "Z:"); + + // An empty path or a path that contains null are not valid paths. + assert!(maybe_verbatim(Path::new("")).is_err()); + assert!(maybe_verbatim(Path::new("\0")).is_err()); +} diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index 87ea416bf67..de73e9154b4 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -2,18 +2,6 @@ use crate::io; use crate::mem; use crate::sys::c; -#[cfg(not(target_vendor = "uwp"))] -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = - unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); - } - v -} - -#[cfg(target_vendor = "uwp")] pub fn hashmap_random_keys() -> (u64, u64) { use crate::ptr; diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 9508bd7da59..0629859bd9d 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -686,7 +686,7 @@ impl Wtf8 { } } -/// Returns a slice of the given string for the byte range [`begin`..`end`). +/// Returns a slice of the given string for the byte range \[`begin`..`end`). /// /// # Panics /// diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index b2aa500a0fd..0c1ffeb1a79 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -257,6 +257,7 @@ pub const fn require_unstable_const_init_thread_local() {} /// [`unwrap`]: crate::result::Result::unwrap /// [naming-threads]: ./index.html#naming-threads /// [stack-size]: ./index.html#stack-size +#[must_use = "must eventually spawn the thread"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Builder { @@ -1449,6 +1450,10 @@ fn _assert_sync_and_send() { /// global state in order to more accurately query the amount of available /// parallelism. /// +/// Resource limits can be changed during the runtime of a program, therefore the value is +/// not cached and instead recomputed every time this function is called. It should not be +/// called from hot code. +/// /// The value returned by this function should be considered a simplified /// approximation of the actual amount of parallelism available at any given /// time. To get a more detailed or precise overview of the amount of diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 5efd8c9be56..3e27e3a4297 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -268,6 +268,20 @@ impl Instant { // // To hopefully mitigate the impact of this, a few platforms are // excluded as "these at least haven't gone backwards yet". + // + // While issues have been seen on arm64 platforms the Arm architecture + // requires that the counter monotonically increases and that it must + // provide a uniform view of system time (e.g. it must not be possible + // for a core to recieve a message from another core with a time stamp + // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While + // there have been a few 64bit SoCs that have bugs which cause time to + // not monoticially increase, these have been fixed in the Linux kernel + // and we shouldn't penalize all Arm SoCs for those who refuse to + // update their kernels: + // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1 + // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10 + // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11 + // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12 if time::Instant::actually_monotonic() { return Instant(os_now); } |
