From 08f761fb838a43589a30c8d5f9c26c11f7102bc8 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Tue, 2 Apr 2024 18:54:24 +0200 Subject: [PATCH 1/9] DOC: Add FFI example for slice::from_raw_parts() --- core/src/slice/raw.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index 29a12f106c5ed..d001688d79d80 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -83,6 +83,27 @@ use crate::ub_checks; /// } /// ``` /// +/// ### FFI: Handling null pointers +/// +/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null. +/// When accepting such pointers, they have to be checked for null-ness to avoid undefined +/// behavior. +/// +/// ``` +/// use std::slice; +/// +/// unsafe extern "C" fn handle_slice(ptr: *const f32, len: usize) { +/// let data = if ptr.is_null() { +/// // `len` is assumed to be 0. +/// &[] +/// } else { +/// unsafe { slice::from_raw_parts(ptr, len) } +/// }; +/// dbg!(data); +/// // ... +/// } +/// ``` +/// /// [valid]: ptr#safety /// [`NonNull::dangling()`]: ptr::NonNull::dangling #[inline] From 678e5a09970d735d96e4255ec2becd9797e7b4b5 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Fri, 26 Apr 2024 20:44:59 +0200 Subject: [PATCH 2/9] Add "safety" comment --- core/src/slice/raw.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index d001688d79d80..8ff429218a4df 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -92,11 +92,16 @@ use crate::ub_checks; /// ``` /// use std::slice; /// +/// /// # Safety +/// /// +/// /// If ptr is not NULL, it must be correctly aligned and +/// /// point to `len` initialized items of type `f32`. /// unsafe extern "C" fn handle_slice(ptr: *const f32, len: usize) { /// let data = if ptr.is_null() { /// // `len` is assumed to be 0. /// &[] /// } else { +/// // SAFETY: see function docstring. /// unsafe { slice::from_raw_parts(ptr, len) } /// }; /// dbg!(data); From 2a5af324d19a923b40330a89947759cf1930162f Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Fri, 26 Apr 2024 20:53:23 +0200 Subject: [PATCH 3/9] Extend the example code and assert the result --- core/src/slice/raw.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index 8ff429218a4df..efdd210c1fac8 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -92,11 +92,13 @@ use crate::ub_checks; /// ``` /// use std::slice; /// +/// /// Sum the elements of an FFI slice. +/// /// /// /// # Safety /// /// /// /// If ptr is not NULL, it must be correctly aligned and /// /// point to `len` initialized items of type `f32`. -/// unsafe extern "C" fn handle_slice(ptr: *const f32, len: usize) { +/// unsafe extern "C" fn sum_slice(ptr: *const f32, len: usize) -> f32 { /// let data = if ptr.is_null() { /// // `len` is assumed to be 0. /// &[] @@ -104,9 +106,14 @@ use crate::ub_checks; /// // SAFETY: see function docstring. /// unsafe { slice::from_raw_parts(ptr, len) } /// }; -/// dbg!(data); -/// // ... +/// data.sum() /// } +/// +/// // This could be the result of C++'s std::vector::data(): +/// let ptr = std::ptr::null(); +/// // And this could be std::vector::size(): +/// let len = 0; +/// assert_eq!(unsafe { sum_slice(ptr, len) }, 0.0); /// ``` /// /// [valid]: ptr#safety From f5305c1c49a9b5548da8c3ac762ecc8ea8673a1f Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Fri, 26 Apr 2024 21:18:00 +0200 Subject: [PATCH 4/9] Add missing .into_iter() --- core/src/slice/raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index efdd210c1fac8..a42c2cc4e63a9 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -106,7 +106,7 @@ use crate::ub_checks; /// // SAFETY: see function docstring. /// unsafe { slice::from_raw_parts(ptr, len) } /// }; -/// data.sum() +/// data.into_iter().sum() /// } /// /// // This could be the result of C++'s std::vector::data(): From e25ae61e2b509dfd378a5b40071b6ebb039b9849 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sun, 9 Jun 2024 20:22:46 -0400 Subject: [PATCH 5/9] docs(core): make more const_ptr doctests assert instead of printing fixes #124669 --- core/src/ptr/const_ptr.rs | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 8c02aee8bfb40..b1f94caed3513 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -330,7 +330,7 @@ impl *const T { /// /// unsafe { /// if let Some(val_back) = ptr.as_ref() { - /// println!("We got back the value: {val_back}!"); + /// assert_eq!(val_back, &10); /// } /// } /// ``` @@ -346,7 +346,7 @@ impl *const T { /// /// unsafe { /// let val_back = &*ptr; - /// println!("We got back the value: {val_back}!"); + /// assert_eq!(val_back, &10); /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] @@ -393,7 +393,7 @@ impl *const T { /// let ptr: *const u8 = &10u8 as *const u8; /// /// unsafe { - /// println!("We got back the value: {}!", ptr.as_ref_unchecked()); + /// assert_eq!(ptr.as_ref_unchecked(), &10); /// } /// ``` // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. @@ -439,7 +439,7 @@ impl *const T { /// /// unsafe { /// if let Some(val_back) = ptr.as_uninit_ref() { - /// println!("We got back the value: {}!", val_back.assume_init()); + /// assert_eq!(val_back.assume_init(), 10); /// } /// } /// ``` @@ -501,8 +501,8 @@ impl *const T { /// let ptr: *const u8 = s.as_ptr(); /// /// unsafe { - /// println!("{}", *ptr.offset(1) as char); - /// println!("{}", *ptr.offset(2) as char); + /// assert_eq!(*ptr.offset(1) as char, '2'); + /// assert_eq!(*ptr.offset(2) as char, '3'); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -573,19 +573,21 @@ impl *const T { /// # Examples /// /// ``` + /// # use std::fmt::Write; /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); /// let step = 2; /// let end_rounded_up = ptr.wrapping_offset(6); /// - /// // This loop prints "1, 3, 5, " + /// let mut out = String::new(); /// while ptr != end_rounded_up { /// unsafe { - /// print!("{}, ", *ptr); + /// write!(&mut out, "{}, ", *ptr).unwrap(); /// } /// ptr = ptr.wrapping_offset(step); /// } + /// assert_eq!(out.as_str(), "1, 3, 5, "); /// ``` #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] @@ -988,8 +990,8 @@ impl *const T { /// let ptr: *const u8 = s.as_ptr(); /// /// unsafe { - /// println!("{}", *ptr.add(1) as char); - /// println!("{}", *ptr.add(2) as char); + /// assert_eq!(*ptr.add(1), b'2'); + /// assert_eq!(*ptr.add(2), b'3'); /// } /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] @@ -1073,8 +1075,8 @@ impl *const T { /// /// unsafe { /// let end: *const u8 = s.as_ptr().add(3); - /// println!("{}", *end.sub(1) as char); - /// println!("{}", *end.sub(2) as char); + /// assert_eq!(*end.sub(1), b'3'); + /// assert_eq!(*end.sub(2), b'2'); /// } /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] @@ -1155,19 +1157,21 @@ impl *const T { /// # Examples /// /// ``` + /// # use std::fmt::Write; /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); /// let step = 2; /// let end_rounded_up = ptr.wrapping_add(6); /// - /// // This loop prints "1, 3, 5, " + /// let mut out = String::new(); /// while ptr != end_rounded_up { /// unsafe { - /// print!("{}, ", *ptr); + /// write!(&mut out, "{}, ", *ptr).unwrap(); /// } /// ptr = ptr.wrapping_add(step); /// } + /// assert_eq!(out, "1, 3, 5, "); /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] @@ -1234,19 +1238,21 @@ impl *const T { /// # Examples /// /// ``` + /// # use std::fmt::Write; /// // Iterate using a raw pointer in increments of two elements (backwards) /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); /// let start_rounded_down = ptr.wrapping_sub(2); /// ptr = ptr.wrapping_add(4); /// let step = 2; - /// // This loop prints "5, 3, 1, " + /// let mut out = String::new(); /// while ptr != start_rounded_down { /// unsafe { - /// print!("{}, ", *ptr); + /// write!(&mut out, "{}, ", *ptr).unwrap(); /// } /// ptr = ptr.wrapping_sub(step); /// } + /// assert_eq!(out, "5, 3, 1, "); /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] From 483f641ee136e18f58c79f3f43600ee1dc39b788 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 10 Jun 2024 17:55:28 -0700 Subject: [PATCH 6/9] Simplify `[T; N]::try_map` signature People keep making fun of this signature for being so gnarly. Associated type bounds lend it a much simpler scribbling. ChangeOutputType can also come along for the ride. --- core/src/array/mod.rs | 6 ++---- core/src/ops/try_trait.rs | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index 05874ab6c4cbb..2569ce237077e 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -533,11 +533,9 @@ impl [T; N] { /// assert_eq!(c, Some(a)); /// ``` #[unstable(feature = "array_try_map", issue = "79711")] - pub fn try_map(self, f: F) -> ChangeOutputType + pub fn try_map(self, f: impl FnMut(T) -> R) -> ChangeOutputType where - F: FnMut(T) -> R, - R: Try, - R::Residual: Residual<[R::Output; N]>, + R: Try>, { drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f))) } diff --git a/core/src/ops/try_trait.rs b/core/src/ops/try_trait.rs index 483f55b207093..cd444c86ed06e 100644 --- a/core/src/ops/try_trait.rs +++ b/core/src/ops/try_trait.rs @@ -363,7 +363,9 @@ pub trait Residual { } #[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")] -pub(crate) type ChangeOutputType = <::Residual as Residual>::TryType; +#[allow(type_alias_bounds)] +pub(crate) type ChangeOutputType>, V> = + >::TryType; /// An adapter for implementing non-try methods via the `Try` implementation. /// From b3dcee6939669eaef36128c43a76072031b4f863 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 11 Jun 2024 17:12:20 +0000 Subject: [PATCH 7/9] set_env: State the conclusion upfront --- std/src/env.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/std/src/env.rs b/std/src/env.rs index 4d649f8a6f136..295e782639bd6 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -323,8 +323,10 @@ impl Error for VarError { /// This function is also always safe to call on Windows, in single-threaded /// and multi-threaded programs. /// -/// In multi-threaded programs on other operating systems, we strongly suggest -/// not using `set_var` or `remove_var` at all. The exact requirement is: you +/// In multi-threaded programs on other operating systems, the only safe option is +/// to not use `set_var` or `remove_var` at all. +/// +/// The exact requirement is: you /// must ensure that there are no other threads concurrently writing or /// *reading*(!) the environment through functions or global variables other /// than the ones in this module. The problem is that these operating systems @@ -390,8 +392,10 @@ unsafe fn _set_var(key: &OsStr, value: &OsStr) { /// This function is also always safe to call on Windows, in single-threaded /// and multi-threaded programs. /// -/// In multi-threaded programs on other operating systems, we strongly suggest -/// not using `set_var` or `remove_var` at all. The exact requirement is: you +/// In multi-threaded programs on other operating systems, the only safe option is +/// to not use `set_var` or `remove_var` at all. +/// +/// The exact requirement is: you /// must ensure that there are no other threads concurrently writing or /// *reading*(!) the environment through functions or global variables other /// than the ones in this module. The problem is that these operating systems From 548e7a4135e08a14ffa2cef450aff612431a69cd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Jun 2024 15:01:57 +1000 Subject: [PATCH 8/9] Update a cranelift patch file for formatting changes. PR #125443 will reformat all the use declarations in the repo. This would break a patch kept in `rustc_codegen_cranelift` that gets applied to `library/std/src/sys/pal/windows/rand.rs`. So this commit formats the use declarations in `library/std/src/sys/pal/windows/rand.rs` in advance of #125443 and updates the patch file accordingly. The motivation is that #125443 is a huge change and we want to get fiddly little changes like this out of the way so it can be nothing more than an `x fmt --all`. --- std/src/sys/pal/windows/rand.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/sys/pal/windows/rand.rs b/std/src/sys/pal/windows/rand.rs index e427546222aea..09f527a09bf12 100644 --- a/std/src/sys/pal/windows/rand.rs +++ b/std/src/sys/pal/windows/rand.rs @@ -1,6 +1,6 @@ +use core::{mem, ptr}; + use crate::sys::c; -use core::mem; -use core::ptr; #[cfg(not(target_vendor = "win7"))] #[inline] From 382ed528dc83228665c84b2e7b91436fea33b31c Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 11 Jun 2024 22:55:55 -0700 Subject: [PATCH 9/9] Make PathBuf less Ok with adding UTF-16 then `into_string` --- std/src/sys_common/wtf8.rs | 3 +++ std/tests/windows.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 std/tests/windows.rs diff --git a/std/src/sys_common/wtf8.rs b/std/src/sys_common/wtf8.rs index bb1e505285bf1..84128a4b595f7 100644 --- a/std/src/sys_common/wtf8.rs +++ b/std/src/sys_common/wtf8.rs @@ -477,6 +477,9 @@ impl Wtf8Buf { /// Part of a hack to make PathBuf::push/pop more efficient. #[inline] pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { + // FIXME: this function should not even exist, as it implies violating Wtf8Buf invariants + // For now, simply assume that is about to happen. + self.is_known_utf8 = false; &mut self.bytes } } diff --git a/std/tests/windows.rs b/std/tests/windows.rs new file mode 100644 index 0000000000000..9f7596f1bc2c0 --- /dev/null +++ b/std/tests/windows.rs @@ -0,0 +1,14 @@ +#![cfg(windows)] +//! An external tests + +use std::{ffi::OsString, os::windows::ffi::OsStringExt, path::PathBuf}; + +#[test] +#[should_panic] +fn os_string_must_know_it_isnt_utf8_issue_126291() { + let mut utf8 = PathBuf::from(OsString::from("utf8".to_owned())); + let non_utf8: OsString = + OsStringExt::from_wide(&[0x6e, 0x6f, 0x6e, 0xd800, 0x75, 0x74, 0x66, 0x38]); + utf8.set_extension(&non_utf8); + utf8.into_os_string().into_string().unwrap(); +}