about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/env.rs26
-rw-r--r--library/std/src/io/mod.rs24
-rw-r--r--library/std/src/macros.rs3
-rw-r--r--library/std/src/net/ip.rs84
-rw-r--r--library/std/src/net/ip/tests.rs17
-rw-r--r--library/std/src/os/linux/mod.rs1
-rw-r--r--library/std/src/os/linux/process.rs154
-rw-r--r--library/std/src/panic.rs313
-rw-r--r--library/std/src/process.rs2
-rw-r--r--library/std/src/sys/hermit/mod.rs3
-rw-r--r--library/std/src/sys/hermit/os.rs9
-rw-r--r--library/std/src/sys/sgx/mod.rs4
-rw-r--r--library/std/src/sys/sgx/os.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs3
-rw-r--r--library/std/src/sys/unix/os.rs9
-rw-r--r--library/std/src/sys/unix/os_str.rs (renamed from library/std/src/sys_common/os_str_bytes.rs)1
-rw-r--r--library/std/src/sys/unix/os_str/tests.rs (renamed from library/std/src/sys_common/os_str_bytes/tests.rs)0
-rw-r--r--library/std/src/sys/unix/process/process_common.rs41
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs136
-rw-r--r--library/std/src/sys/unix/weak.rs5
-rw-r--r--library/std/src/sys/unsupported/common.rs2
-rw-r--r--library/std/src/sys/unsupported/mod.rs2
-rw-r--r--library/std/src/sys/unsupported/os.rs4
-rw-r--r--library/std/src/sys/wasi/mod.rs3
-rw-r--r--library/std/src/sys/wasi/os.rs9
-rw-r--r--library/std/src/sys/wasm/mod.rs4
-rw-r--r--library/std/src/sys/windows/os.rs19
-rw-r--r--library/std/src/sys_common/mod.rs4
28 files changed, 436 insertions, 450 deletions
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 79b7e2e57a3..f9f14d0dc63 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -185,15 +185,9 @@ impl fmt::Debug for VarsOs {
 ///
 /// # Errors
 ///
-/// Errors if the environment variable is not present.
-/// Errors if the environment variable is not valid Unicode. If this is not desired, consider using
-/// [`var_os`].
-///
-/// # Panics
-///
-/// This function may panic if `key` is empty, contains an ASCII equals sign
-/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
-/// character.
+/// Returns `[None]` if the environment variable isn't set.
+/// Returns `[None]` if the environment variable is not valid Unicode. If this is not
+/// desired, consider using [`var_os`].
 ///
 /// # Examples
 ///
@@ -219,18 +213,17 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
 }
 
 /// Fetches the environment variable `key` from the current process, returning
-/// [`None`] if the variable isn't set.
-///
-/// # Panics
-///
-/// This function may panic if `key` is empty, contains an ASCII equals sign
-/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
-/// character.
+/// [`None`] if the variable isn't set or there's another error.
 ///
 /// Note that the method will not check if the environment variable
 /// is valid Unicode. If you want to have an error on invalid UTF-8,
 /// use the [`var`] function instead.
 ///
+/// # Errors
+///
+/// Returns `[None]` if the variable isn't set.
+/// May return `[None]` if the variable value contains the NUL character.
+///
 /// # Examples
 ///
 /// ```
@@ -249,7 +242,6 @@ pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
 
 fn _var_os(key: &OsStr) -> Option<OsString> {
     os_imp::getenv(key)
-        .unwrap_or_else(|e| panic!("failed to get environment variable `{:?}`: {}", key, e))
 }
 
 /// The error type for operations interacting with environment variables.
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index b336b65ad7d..fa073d080c6 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -810,9 +810,9 @@ pub trait Read {
         default_read_exact(self, buf)
     }
 
-    /// Creates a "by reference" adaptor for this instance of `Read`.
+    /// Creates a "by reference" adapter for this instance of `Read`.
     ///
-    /// The returned adaptor also implements `Read` and will simply borrow this
+    /// The returned adapter also implements `Read` and will simply borrow this
     /// current reader.
     ///
     /// # Examples
@@ -889,7 +889,7 @@ pub trait Read {
         Bytes { inner: self }
     }
 
-    /// Creates an adaptor which will chain this stream with another.
+    /// Creates an adapter which will chain this stream with another.
     ///
     /// The returned `Read` instance will first read all bytes from this object
     /// until EOF is encountered. Afterwards the output is equivalent to the
@@ -927,7 +927,7 @@ pub trait Read {
         Chain { first: self, second: next, done_first: false }
     }
 
-    /// Creates an adaptor which will read at most `limit` bytes from it.
+    /// Creates an adapter which will read at most `limit` bytes from it.
     ///
     /// This function returns a new instance of `Read` which will read at most
     /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
@@ -1326,7 +1326,7 @@ impl Initializer {
 /// * The [`write`] method will attempt to write some data into the object,
 ///   returning how many bytes were successfully written.
 ///
-/// * The [`flush`] method is useful for adaptors and explicit buffers
+/// * The [`flush`] method is useful for adapters and explicit buffers
 ///   themselves for ensuring that all buffered data has been pushed out to the
 ///   'true sink'.
 ///
@@ -1646,12 +1646,12 @@ pub trait Write {
     fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
         // Create a shim which translates a Write to a fmt::Write and saves
         // off I/O errors. instead of discarding them
-        struct Adaptor<'a, T: ?Sized + 'a> {
+        struct Adapter<'a, T: ?Sized + 'a> {
             inner: &'a mut T,
             error: Result<()>,
         }
 
-        impl<T: Write + ?Sized> fmt::Write for Adaptor<'_, T> {
+        impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
             fn write_str(&mut self, s: &str) -> fmt::Result {
                 match self.inner.write_all(s.as_bytes()) {
                     Ok(()) => Ok(()),
@@ -1663,7 +1663,7 @@ pub trait Write {
             }
         }
 
-        let mut output = Adaptor { inner: self, error: Ok(()) };
+        let mut output = Adapter { inner: self, error: Ok(()) };
         match fmt::write(&mut output, fmt) {
             Ok(()) => Ok(()),
             Err(..) => {
@@ -1677,9 +1677,9 @@ pub trait Write {
         }
     }
 
-    /// Creates a "by reference" adaptor for this instance of `Write`.
+    /// Creates a "by reference" adapter for this instance of `Write`.
     ///
-    /// The returned adaptor also implements `Write` and will simply borrow this
+    /// The returned adapter also implements `Write` and will simply borrow this
     /// current writer.
     ///
     /// # Examples
@@ -2263,7 +2263,7 @@ pub trait BufRead: Read {
     }
 }
 
-/// Adaptor to chain together two readers.
+/// Adapter to chain together two readers.
 ///
 /// This struct is generally created by calling [`chain`] on a reader.
 /// Please see the documentation of [`chain`] for more details.
@@ -2414,7 +2414,7 @@ impl<T, U> SizeHint for Chain<T, U> {
     }
 }
 
-/// Reader adaptor which limits the bytes read from an underlying reader.
+/// Reader adapter which limits the bytes read from an underlying reader.
 ///
 /// This struct is generally created by calling [`take`] on a reader.
 /// Please see the documentation of [`take`] for more details.
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 676695795ba..5dc75d32ec8 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -6,8 +6,7 @@
 
 #[doc = include_str!("../../core/src/macros/panic.md")]
 #[macro_export]
-#[cfg_attr(bootstrap, rustc_builtin_macro = "std_panic")]
-#[cfg_attr(not(bootstrap), rustc_builtin_macro(std_panic))]
+#[rustc_builtin_macro(std_panic)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable(edition_panic)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")]
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 88309875978..a23e29c5c76 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -116,16 +116,58 @@ pub struct Ipv6Addr {
     inner: c::in6_addr,
 }
 
-#[allow(missing_docs)]
+/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
+///
+/// # Stability Guarantees
+///
+/// Not all possible values for a multicast scope have been assigned.
+/// Future RFCs may introduce new scopes, which will be added as variants to this enum;
+/// because of this the enum is marked as `#[non_exhaustive]`.
+///
+/// # Examples
+/// ```
+/// #![feature(ip)]
+///
+/// use std::net::Ipv6Addr;
+/// use std::net::Ipv6MulticastScope::*;
+///
+/// // An IPv6 multicast address with global scope (`ff0e::`).
+/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0);
+///
+/// // Will print "Global scope".
+/// match address.multicast_scope() {
+///     Some(InterfaceLocal) => println!("Interface-Local scope"),
+///     Some(LinkLocal) => println!("Link-Local scope"),
+///     Some(RealmLocal) => println!("Realm-Local scope"),
+///     Some(AdminLocal) => println!("Admin-Local scope"),
+///     Some(SiteLocal) => println!("Site-Local scope"),
+///     Some(OrganizationLocal) => println!("Organization-Local scope"),
+///     Some(Global) => println!("Global scope"),
+///     Some(_) => println!("Unknown scope"),
+///     None => println!("Not a multicast address!")
+/// }
+///
+/// ```
+///
+/// [IPv6 multicast address]: Ipv6Addr
+/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2
 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
 #[unstable(feature = "ip", issue = "27709")]
+#[non_exhaustive]
 pub enum Ipv6MulticastScope {
+    /// Interface-Local scope.
     InterfaceLocal,
+    /// Link-Local scope.
     LinkLocal,
+    /// Realm-Local scope.
     RealmLocal,
+    /// Admin-Local scope.
     AdminLocal,
+    /// Site-Local scope.
     SiteLocal,
+    /// Organization-Local scope.
     OrganizationLocal,
+    /// Global scope.
     Global,
 }
 
@@ -486,8 +528,7 @@ impl Ipv4Addr {
     /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
     /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
     ///   `0.0.0.0/8` block
-    /// - addresses reserved for future protocols (see
-    /// [`Ipv4Addr::is_ietf_protocol_assignment()`], except
+    /// - addresses reserved for future protocols, except
     /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
     /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`]
     /// - addresses reserved for networking devices benchmarking (see
@@ -560,7 +601,8 @@ impl Ipv4Addr {
             && !self.is_broadcast()
             && !self.is_documentation()
             && !self.is_shared()
-            && !self.is_ietf_protocol_assignment()
+            // addresses reserved for future protocols (`192.0.0.0/24`)
+            && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
             && !self.is_reserved()
             && !self.is_benchmarking()
             // Make sure the address is not in 0.0.0.0/8
@@ -589,40 +631,6 @@ impl Ipv4Addr {
         self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
     }
 
-    /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to
-    /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890].
-    ///
-    /// Note that parts of this block are in use:
-    ///
-    /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600])
-    /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723])
-    /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155])
-    ///
-    /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890
-    /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600
-    /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723
-    /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true);
-    /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true);
-    /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true);
-    /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true);
-    /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false);
-    /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[inline]
-    pub const fn is_ietf_protocol_assignment(&self) -> bool {
-        self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
-    }
-
     /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
     /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
     /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index 2109980ad05..dbfab9dde40 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -339,7 +339,6 @@ fn ipv4_properties() {
             let broadcast: u16 = 1 << 6;
             let documentation: u16 = 1 << 7;
             let benchmarking: u16 = 1 << 8;
-            let ietf_protocol_assignment: u16 = 1 << 9;
             let reserved: u16 = 1 << 10;
             let shared: u16 = 1 << 11;
 
@@ -397,12 +396,6 @@ fn ipv4_properties() {
                 assert!(!ip!($s).is_benchmarking());
             }
 
-            if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment {
-                assert!(ip!($s).is_ietf_protocol_assignment());
-            } else {
-                assert!(!ip!($s).is_ietf_protocol_assignment());
-            }
-
             if ($mask & reserved) == reserved {
                 assert!(ip!($s).is_reserved());
             } else {
@@ -426,7 +419,6 @@ fn ipv4_properties() {
     let broadcast: u16 = 1 << 6;
     let documentation: u16 = 1 << 7;
     let benchmarking: u16 = 1 << 8;
-    let ietf_protocol_assignment: u16 = 1 << 9;
     let reserved: u16 = 1 << 10;
     let shared: u16 = 1 << 11;
 
@@ -449,9 +441,9 @@ fn ipv4_properties() {
     check!("198.18.0.0", benchmarking);
     check!("198.18.54.2", benchmarking);
     check!("198.19.255.255", benchmarking);
-    check!("192.0.0.0", ietf_protocol_assignment);
-    check!("192.0.0.255", ietf_protocol_assignment);
-    check!("192.0.0.100", ietf_protocol_assignment);
+    check!("192.0.0.0");
+    check!("192.0.0.255");
+    check!("192.0.0.100");
     check!("240.0.0.0", reserved);
     check!("251.54.1.76", reserved);
     check!("254.255.255.255", reserved);
@@ -823,9 +815,6 @@ fn ipv4_const() {
     const IS_SHARED: bool = IP_ADDRESS.is_shared();
     assert!(!IS_SHARED);
 
-    const IS_IETF_PROTOCOL_ASSIGNMENT: bool = IP_ADDRESS.is_ietf_protocol_assignment();
-    assert!(!IS_IETF_PROTOCOL_ASSIGNMENT);
-
     const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
     assert!(!IS_BENCHMARKING);
 
diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs
index 94438defc22..8e7776f6646 100644
--- a/library/std/src/os/linux/mod.rs
+++ b/library/std/src/os/linux/mod.rs
@@ -4,4 +4,5 @@
 #![doc(cfg(target_os = "linux"))]
 
 pub mod fs;
+pub mod process;
 pub mod raw;
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
new file mode 100644
index 00000000000..91547b8f916
--- /dev/null
+++ b/library/std/src/os/linux/process.rs
@@ -0,0 +1,154 @@
+//! Linux-specific extensions to primitives in the `std::process` module.
+
+#![unstable(feature = "linux_pidfd", issue = "82971")]
+
+use crate::io::Result;
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::process;
+#[cfg(not(doc))]
+use crate::sys::fd::FileDesc;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[cfg(doc)]
+struct FileDesc;
+
+/// This type represents a file descriptor that refers to a process.
+///
+/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
+/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
+/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
+///
+/// Example:
+/// ```no_run
+/// #![feature(linux_pidfd)]
+/// use std::os::linux::process::{CommandExt, ChildExt};
+/// use std::process::Command;
+///
+/// let mut child = Command::new("echo")
+///     .create_pidfd(true)
+///     .spawn()
+///     .expect("Failed to spawn child");
+///
+/// let pidfd = child
+///     .take_pidfd()
+///     .expect("Failed to retrieve pidfd");
+///
+/// // The file descriptor will be closed when `pidfd` is dropped.
+/// ```
+/// Refer to the man page of [`pidfd_open(2)`] for further details.
+///
+/// [`Command`]: process::Command
+/// [`create_pidfd`]: CommandExt::create_pidfd
+/// [`Child`]: process::Child
+/// [`pidfd`]: fn@ChildExt::pidfd
+/// [`take_pidfd`]: ChildExt::take_pidfd
+/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
+#[derive(Debug)]
+pub struct PidFd {
+    inner: FileDesc,
+}
+
+impl AsInner<FileDesc> for PidFd {
+    fn as_inner(&self) -> &FileDesc {
+        &self.inner
+    }
+}
+
+impl FromInner<FileDesc> for PidFd {
+    fn from_inner(inner: FileDesc) -> PidFd {
+        PidFd { inner }
+    }
+}
+
+impl IntoInner<FileDesc> for PidFd {
+    fn into_inner(self) -> FileDesc {
+        self.inner
+    }
+}
+
+impl AsRawFd for PidFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().raw()
+    }
+}
+
+impl FromRawFd for PidFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        Self::from_inner(FileDesc::new(fd))
+    }
+}
+
+impl IntoRawFd for PidFd {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_raw()
+    }
+}
+
+mod private_child_ext {
+    pub trait Sealed {}
+    impl Sealed for crate::process::Child {}
+}
+
+/// Os-specific extensions for [`Child`]
+///
+/// [`Child`]: process::Child
+pub trait ChildExt: private_child_ext::Sealed {
+    /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
+    ///
+    /// A pidfd will only be available if its creation was requested with
+    /// [`create_pidfd`] when the corresponding [`Command`] was created.
+    ///
+    /// Even if requested, a pidfd may not be available due to an older
+    /// version of Linux being in use, or if some other error occurred.
+    ///
+    /// [`Command`]: process::Command
+    /// [`create_pidfd`]: CommandExt::create_pidfd
+    /// [`Child`]: process::Child
+    fn pidfd(&self) -> Result<&PidFd>;
+
+    /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
+    ///
+    /// A pidfd will only be available if its creation was requested with
+    /// [`create_pidfd`] when the corresponding [`Command`] was created.
+    ///
+    /// Even if requested, a pidfd may not be available due to an older
+    /// version of Linux being in use, or if some other error occurred.
+    ///
+    /// [`Command`]: process::Command
+    /// [`create_pidfd`]: CommandExt::create_pidfd
+    /// [`Child`]: process::Child
+    fn take_pidfd(&mut self) -> Result<PidFd>;
+}
+
+mod private_command_ext {
+    pub trait Sealed {}
+    impl Sealed for crate::process::Command {}
+}
+
+/// Os-specific extensions for [`Command`]
+///
+/// [`Command`]: process::Command
+pub trait CommandExt: private_command_ext::Sealed {
+    /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
+    /// spawned by this [`Command`].
+    /// By default, no pidfd will be created.
+    ///
+    /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
+    ///
+    /// A pidfd will only be created if it is possible to do so
+    /// in a guaranteed race-free manner (e.g. if the `clone3` system call
+    /// is supported). Otherwise, [`pidfd`] will return an error.
+    ///
+    /// [`Command`]: process::Command
+    /// [`Child`]: process::Child
+    /// [`pidfd`]: fn@ChildExt::pidfd
+    /// [`take_pidfd`]: ChildExt::take_pidfd
+    fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
+}
+
+impl CommandExt for process::Command {
+    fn create_pidfd(&mut self, val: bool) -> &mut process::Command {
+        self.as_inner_mut().create_pidfd(val);
+        self
+    }
+}
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 9c597e17bb5..c1c03958497 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -3,19 +3,9 @@
 #![stable(feature = "std_panic", since = "1.9.0")]
 
 use crate::any::Any;
-use crate::cell::UnsafeCell;
 use crate::collections;
-use crate::fmt;
-use crate::future::Future;
-use crate::ops::{Deref, DerefMut};
 use crate::panicking;
-use crate::pin::Pin;
-use crate::ptr::{NonNull, Unique};
-use crate::rc::Rc;
-use crate::stream::Stream;
-use crate::sync::atomic;
-use crate::sync::{Arc, Mutex, RwLock};
-use crate::task::{Context, Poll};
+use crate::sync::{Mutex, RwLock};
 use crate::thread::Result;
 
 #[doc(hidden)]
@@ -45,6 +35,9 @@ pub use crate::panicking::{set_hook, take_hook};
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub use core::panic::{Location, PanicInfo};
 
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
+
 /// Panic the current thread with the given message as the panic payload.
 ///
 /// The message can be of any (`Any + Send`) type, not just strings.
@@ -60,259 +53,16 @@ pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
     crate::panicking::begin_panic(msg);
 }
 
-/// A marker trait which represents "panic safe" types in Rust.
-///
-/// This trait is implemented by default for many types and behaves similarly in
-/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The
-/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`]
-/// boundary with no fear of unwind safety.
-///
-/// ## What is unwind safety?
-///
-/// In Rust a function can "return" early if it either panics or calls a
-/// function which transitively panics. This sort of control flow is not always
-/// anticipated, and has the possibility of causing subtle bugs through a
-/// combination of two critical components:
-///
-/// 1. A data structure is in a temporarily invalid state when the thread
-///    panics.
-/// 2. This broken invariant is then later observed.
-///
-/// Typically in Rust, it is difficult to perform step (2) because catching a
-/// panic involves either spawning a thread (which in turns makes it difficult
-/// to later witness broken invariants) or using the `catch_unwind` function in this
-/// module. Additionally, even if an invariant is witnessed, it typically isn't a
-/// problem in Rust because there are no uninitialized values (like in C or C++).
-///
-/// It is possible, however, for **logical** invariants to be broken in Rust,
-/// which can end up causing behavioral bugs. Another key aspect of unwind safety
-/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
-/// memory unsafety.
-///
-/// That was a bit of a whirlwind tour of unwind safety, but for more information
-/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc].
-///
-/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
-///
-/// ## What is `UnwindSafe`?
-///
-/// Now that we've got an idea of what unwind safety is in Rust, it's also
-/// important to understand what this trait represents. As mentioned above, one
-/// way to witness broken invariants is through the `catch_unwind` function in this
-/// module as it allows catching a panic and then re-using the environment of
-/// the closure.
-///
-/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
-/// witnessing a broken invariant through the use of `catch_unwind` (catching a
-/// panic). This trait is an auto trait, so it is automatically implemented for
-/// many types, and it is also structurally composed (e.g., a struct is unwind
-/// safe if all of its components are unwind safe).
-///
-/// Note, however, that this is not an unsafe trait, so there is not a succinct
-/// contract that this trait is providing. Instead it is intended as more of a
-/// "speed bump" to alert users of `catch_unwind` that broken invariants may be
-/// witnessed and may need to be accounted for.
-///
-/// ## Who implements `UnwindSafe`?
-///
-/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
-/// unwind safe. The general idea is that any mutable state which can be shared
-/// across `catch_unwind` is not unwind safe by default. This is because it is very
-/// easy to witness a broken invariant outside of `catch_unwind` as the data is
-/// simply accessed as usual.
-///
-/// Types like `&Mutex<T>`, however, are unwind safe because they implement
-/// poisoning by default. They still allow witnessing a broken invariant, but
-/// they already provide their own "speed bumps" to do so.
-///
-/// ## When should `UnwindSafe` be used?
-///
-/// It is not intended that most types or functions need to worry about this trait.
-/// It is only used as a bound on the `catch_unwind` function and as mentioned
-/// above, the lack of `unsafe` means it is mostly an advisory. The
-/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be
-/// implemented for any closed over variables passed to `catch_unwind`.
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "unwind_safe_trait")]
-#[rustc_on_unimplemented(
-    message = "the type `{Self}` may not be safely transferred across an unwind boundary",
-    label = "`{Self}` may not be safely transferred across an unwind boundary"
-)]
-pub auto trait UnwindSafe {}
-
-/// A marker trait representing types where a shared reference is considered
-/// unwind safe.
-///
-/// This trait is namely not implemented by [`UnsafeCell`], the root of all
-/// interior mutability.
-///
-/// This is a "helper marker trait" used to provide impl blocks for the
-/// [`UnwindSafe`] trait, for more information see that documentation.
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "ref_unwind_safe_trait")]
-#[rustc_on_unimplemented(
-    message = "the type `{Self}` may contain interior mutability and a reference may not be safely \
-               transferrable across a catch_unwind boundary",
-    label = "`{Self}` may contain interior mutability and a reference may not be safely \
-             transferrable across a catch_unwind boundary"
-)]
-pub auto trait RefUnwindSafe {}
-
-/// A simple wrapper around a type to assert that it is unwind safe.
-///
-/// When using [`catch_unwind`] it may be the case that some of the closed over
-/// variables are not unwind safe. For example if `&mut T` is captured the
-/// compiler will generate a warning indicating that it is not unwind safe. It
-/// might not be the case, however, that this is actually a problem due to the
-/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into
-/// account. This wrapper struct is useful for a quick and lightweight
-/// annotation that a variable is indeed unwind safe.
-///
-/// # Examples
-///
-/// One way to use `AssertUnwindSafe` is to assert that the entire closure
-/// itself is unwind safe, bypassing all checks for all variables:
-///
-/// ```
-/// use std::panic::{self, AssertUnwindSafe};
-///
-/// let mut variable = 4;
-///
-/// // This code will not compile because the closure captures `&mut variable`
-/// // which is not considered unwind safe by default.
-///
-/// // panic::catch_unwind(|| {
-/// //     variable += 3;
-/// // });
-///
-/// // This, however, will compile due to the `AssertUnwindSafe` wrapper
-/// let result = panic::catch_unwind(AssertUnwindSafe(|| {
-///     variable += 3;
-/// }));
-/// // ...
-/// ```
-///
-/// Wrapping the entire closure amounts to a blanket assertion that all captured
-/// variables are unwind safe. This has the downside that if new captures are
-/// added in the future, they will also be considered unwind safe. Therefore,
-/// you may prefer to just wrap individual captures, as shown below. This is
-/// more annotation, but it ensures that if a new capture is added which is not
-/// unwind safe, you will get a compilation error at that time, which will
-/// allow you to consider whether that new capture in fact represent a bug or
-/// not.
-///
-/// ```
-/// use std::panic::{self, AssertUnwindSafe};
-///
-/// let mut variable = 4;
-/// let other_capture = 3;
-///
-/// let result = {
-///     let mut wrapper = AssertUnwindSafe(&mut variable);
-///     panic::catch_unwind(move || {
-///         **wrapper += other_capture;
-///     })
-/// };
-/// // ...
-/// ```
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-pub struct AssertUnwindSafe<T>(#[stable(feature = "catch_unwind", since = "1.9.0")] pub T);
-
-// Implementations of the `UnwindSafe` trait:
-//
-// * By default everything is unwind safe
-// * pointers T contains mutability of some form are not unwind safe
-// * Unique, an owning pointer, lifts an implementation
-// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe
-// * Our custom AssertUnwindSafe wrapper is indeed unwind safe
-
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: ?Sized> !UnwindSafe for &mut T {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
-#[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
-#[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: ?Sized> UnwindSafe for Mutex<T> {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: ?Sized> UnwindSafe for RwLock<T> {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T> UnwindSafe for AssertUnwindSafe<T> {}
-
-// not covered via the Shared impl above b/c the inner contents use
-// Cell/AtomicUsize, but the usage here is unwind safe so we can lift the
-// impl up one level to Arc/Rc itself
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {}
-
-// Pretty simple implementations for the `RefUnwindSafe` marker trait,
-// basically just saying that `UnsafeCell` is the
-// only thing which doesn't implement it (which then transitively applies to
-// everything else).
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}
 
 #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
 impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
 #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
 impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
 
-#[cfg(target_has_atomic_load_store = "ptr")]
-#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
-impl RefUnwindSafe for atomic::AtomicIsize {}
-#[cfg(target_has_atomic_load_store = "8")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicI8 {}
-#[cfg(target_has_atomic_load_store = "16")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicI16 {}
-#[cfg(target_has_atomic_load_store = "32")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicI32 {}
-#[cfg(target_has_atomic_load_store = "64")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicI64 {}
-#[cfg(target_has_atomic_load_store = "128")]
-#[unstable(feature = "integer_atomics", issue = "32976")]
-impl RefUnwindSafe for atomic::AtomicI128 {}
-
-#[cfg(target_has_atomic_load_store = "ptr")]
-#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
-impl RefUnwindSafe for atomic::AtomicUsize {}
-#[cfg(target_has_atomic_load_store = "8")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicU8 {}
-#[cfg(target_has_atomic_load_store = "16")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicU16 {}
-#[cfg(target_has_atomic_load_store = "32")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicU32 {}
-#[cfg(target_has_atomic_load_store = "64")]
-#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
-impl RefUnwindSafe for atomic::AtomicU64 {}
-#[cfg(target_has_atomic_load_store = "128")]
-#[unstable(feature = "integer_atomics", issue = "32976")]
-impl RefUnwindSafe for atomic::AtomicU128 {}
-
-#[cfg(target_has_atomic_load_store = "8")]
-#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
-impl RefUnwindSafe for atomic::AtomicBool {}
-
-#[cfg(target_has_atomic_load_store = "ptr")]
-#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
-impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {}
-
 // https://github.com/rust-lang/rust/issues/62301
 #[stable(feature = "hashbrown", since = "1.36.0")]
 impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S>
@@ -323,61 +73,6 @@ where
 {
 }
 
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T> Deref for AssertUnwindSafe<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        &self.0
-    }
-}
-
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T> DerefMut for AssertUnwindSafe<T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut self.0
-    }
-}
-
-#[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
-    type Output = R;
-
-    extern "rust-call" fn call_once(self, _args: ()) -> R {
-        (self.0)()
-    }
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("AssertUnwindSafe").field(&self.0).finish()
-    }
-}
-
-#[stable(feature = "futures_api", since = "1.36.0")]
-impl<F: Future> Future for AssertUnwindSafe<F> {
-    type Output = F::Output;
-
-    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
-        F::poll(pinned_field, cx)
-    }
-}
-
-#[unstable(feature = "async_stream", issue = "79024")]
-impl<S: Stream> Stream for AssertUnwindSafe<S> {
-    type Item = S::Item;
-
-    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
-        unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.0.size_hint()
-    }
-}
-
 /// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
 ///
 /// This function will return `Ok` with the closure's result if the closure
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 11a0432ce27..99c3369425b 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -166,7 +166,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 /// [`wait`]: Child::wait
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Child {
-    handle: imp::Process,
+    pub(crate) handle: imp::Process,
 
     /// The handle for writing to the child's standard input (stdin), if it has
     /// been captured. To avoid partially moving
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 10c19424953..185b68c0a78 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -32,6 +32,8 @@ pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
 #[path = "../unix/path.rs"]
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
@@ -47,7 +49,6 @@ pub mod thread_local_key;
 pub mod time;
 
 use crate::io::ErrorKind;
-pub use crate::sys_common::os_str_bytes as os_str;
 
 #[allow(unused_extern_crates)]
 pub extern crate hermit_abi as abi;
diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs
index eeb30a578c0..8f927df85be 100644
--- a/library/std/src/sys/hermit/os.rs
+++ b/library/std/src/sys/hermit/os.rs
@@ -140,13 +140,8 @@ pub fn env() -> Env {
     }
 }
 
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    unsafe {
-        match ENV.as_ref().unwrap().lock().unwrap().get_mut(k) {
-            Some(value) => Ok(Some(value.clone())),
-            None => Ok(None),
-        }
-    }
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    unsafe { ENV.as_ref().unwrap().lock().unwrap().get_mut(k).cloned() }
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index fce6b420732..a2a763c2b4e 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -26,6 +26,8 @@ pub mod memchr;
 pub mod mutex;
 pub mod net;
 pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
@@ -37,8 +39,6 @@ pub mod thread;
 pub mod thread_local_key;
 pub mod time;
 
-pub use crate::sys_common::os_str_bytes as os_str;
-
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
 pub unsafe fn init(argc: isize, argv: *const *const u8) {
diff --git a/library/std/src/sys/sgx/os.rs b/library/std/src/sys/sgx/os.rs
index 144248d60c9..5f8b8def7c6 100644
--- a/library/std/src/sys/sgx/os.rs
+++ b/library/std/src/sys/sgx/os.rs
@@ -106,8 +106,8 @@ pub fn env() -> Env {
     get_env_store().map(|env| clone_to_vec(&env.lock().unwrap())).unwrap_or_default().into_iter()
 }
 
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    Ok(get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned()))
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned())
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 9e553ec7682..f827a4bca53 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -30,6 +30,7 @@ pub mod net;
 #[cfg(target_os = "l4re")]
 pub use self::l4re::net;
 pub mod os;
+pub mod os_str;
 pub mod path;
 pub mod pipe;
 pub mod process;
@@ -42,8 +43,6 @@ pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod time;
 
-pub use crate::sys_common::os_str_bytes as os_str;
-
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
 pub unsafe fn init(argc: isize, argv: *const *const u8) {
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index cc0802ed709..dfbd93c90e6 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -532,19 +532,18 @@ pub fn env() -> Env {
     }
 }
 
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+pub fn getenv(k: &OsStr) -> Option<OsString> {
     // environment variables with a nul byte can't be set, so their value is
     // always None as well
-    let k = CString::new(k.as_bytes())?;
+    let k = CString::new(k.as_bytes()).ok()?;
     unsafe {
         let _guard = env_read_lock();
         let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
-        let ret = if s.is_null() {
+        if s.is_null() {
             None
         } else {
             Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
-        };
-        Ok(ret)
+        }
     }
 }
 
diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys/unix/os_str.rs
index 569600470db..ae96d6b4df4 100644
--- a/library/std/src/sys_common/os_str_bytes.rs
+++ b/library/std/src/sys/unix/os_str.rs
@@ -13,6 +13,7 @@ use crate::sys_common::{AsInner, IntoInner};
 use core::str::lossy::{Utf8Lossy, Utf8LossyChunk};
 
 #[cfg(test)]
+#[path = "../unix/os_str/tests.rs"]
 mod tests;
 
 #[derive(Hash)]
diff --git a/library/std/src/sys_common/os_str_bytes/tests.rs b/library/std/src/sys/unix/os_str/tests.rs
index 37967378155..37967378155 100644
--- a/library/std/src/sys_common/os_str_bytes/tests.rs
+++ b/library/std/src/sys/unix/os_str/tests.rs
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index f2f161e4eaa..a1972380a9f 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -79,6 +79,8 @@ pub struct Command {
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
+    #[cfg(target_os = "linux")]
+    create_pidfd: bool,
 }
 
 // Create a new type for argv, so that we can make it `Send` and `Sync`
@@ -124,6 +126,7 @@ pub enum Stdio {
 }
 
 impl Command {
+    #[cfg(not(target_os = "linux"))]
     pub fn new(program: &OsStr) -> Command {
         let mut saw_nul = false;
         let program = os2c(program, &mut saw_nul);
@@ -144,6 +147,28 @@ impl Command {
         }
     }
 
+    #[cfg(target_os = "linux")]
+    pub fn new(program: &OsStr) -> Command {
+        let mut saw_nul = false;
+        let program = os2c(program, &mut saw_nul);
+        Command {
+            argv: Argv(vec![program.as_ptr(), ptr::null()]),
+            args: vec![program.clone()],
+            program,
+            env: Default::default(),
+            cwd: None,
+            uid: None,
+            gid: None,
+            saw_nul,
+            closures: Vec::new(),
+            groups: None,
+            stdin: None,
+            stdout: None,
+            stderr: None,
+            create_pidfd: false,
+        }
+    }
+
     pub fn set_arg_0(&mut self, arg: &OsStr) {
         // Set a new arg0
         let arg = os2c(arg, &mut self.saw_nul);
@@ -177,6 +202,22 @@ impl Command {
         self.groups = Some(Box::from(groups));
     }
 
+    #[cfg(target_os = "linux")]
+    pub fn create_pidfd(&mut self, val: bool) {
+        self.create_pidfd = val;
+    }
+
+    #[cfg(not(target_os = "linux"))]
+    #[allow(dead_code)]
+    pub fn get_create_pidfd(&self) -> bool {
+        false
+    }
+
+    #[cfg(target_os = "linux")]
+    pub fn get_create_pidfd(&self) -> bool {
+        self.create_pidfd
+    }
+
     pub fn saw_nul(&self) -> bool {
         self.saw_nul
     }
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index c888dd0d87d..4b210d6af13 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -9,6 +9,12 @@ use crate::sys;
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
 
+#[cfg(target_os = "linux")]
+use crate::os::linux::process::PidFd;
+
+#[cfg(target_os = "linux")]
+use crate::sys::weak::syscall;
+
 #[cfg(any(
     target_os = "macos",
     target_os = "freebsd",
@@ -61,7 +67,8 @@ impl Command {
         // a lock any more because the parent won't do anything and the child is
         // in its own process. Thus the parent drops the lock guard while the child
         // forgets it to avoid unlocking it on a new thread, which would be invalid.
-        let (env_lock, pid) = unsafe { (sys::os::env_read_lock(), cvt(libc::fork())?) };
+        let env_lock = sys::os::env_read_lock();
+        let (pid, pidfd) = unsafe { self.do_fork()? };
 
         if pid == 0 {
             crate::panic::always_abort();
@@ -90,7 +97,7 @@ impl Command {
         drop(env_lock);
         drop(output);
 
-        let mut p = Process { pid, status: None };
+        let mut p = Process::new(pid, pidfd);
         let mut bytes = [0; 8];
 
         // loop to handle EINTR
@@ -122,6 +129,92 @@ impl Command {
         }
     }
 
+    // Attempts to fork the process. If successful, returns Ok((0, -1))
+    // in the child, and Ok((child_pid, -1)) in the parent.
+    #[cfg(not(target_os = "linux"))]
+    unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+        cvt(libc::fork()).map(|res| (res, -1))
+    }
+
+    // Attempts to fork the process. If successful, returns Ok((0, -1))
+    // in the child, and Ok((child_pid, child_pidfd)) in the parent.
+    #[cfg(target_os = "linux")]
+    unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+        use crate::sync::atomic::{AtomicBool, Ordering};
+
+        static HAS_CLONE3: AtomicBool = AtomicBool::new(true);
+        const CLONE_PIDFD: u64 = 0x00001000;
+
+        #[repr(C)]
+        struct clone_args {
+            flags: u64,
+            pidfd: u64,
+            child_tid: u64,
+            parent_tid: u64,
+            exit_signal: u64,
+            stack: u64,
+            stack_size: u64,
+            tls: u64,
+            set_tid: u64,
+            set_tid_size: u64,
+            cgroup: u64,
+        }
+
+        syscall! {
+            fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
+        }
+
+        // If we fail to create a pidfd for any reason, this will
+        // stay as -1, which indicates an error.
+        let mut pidfd: pid_t = -1;
+
+        // Attempt to use the `clone3` syscall, which supports more arguments
+        // (in particular, the ability to create a pidfd). If this fails,
+        // we will fall through this block to a call to `fork()`
+        if HAS_CLONE3.load(Ordering::Relaxed) {
+            let mut flags = 0;
+            if self.get_create_pidfd() {
+                flags |= CLONE_PIDFD;
+            }
+
+            let mut args = clone_args {
+                flags,
+                pidfd: &mut pidfd as *mut pid_t as u64,
+                child_tid: 0,
+                parent_tid: 0,
+                exit_signal: libc::SIGCHLD as u64,
+                stack: 0,
+                stack_size: 0,
+                tls: 0,
+                set_tid: 0,
+                set_tid_size: 0,
+                cgroup: 0,
+            };
+
+            let args_ptr = &mut args as *mut clone_args;
+            let args_size = crate::mem::size_of::<clone_args>();
+
+            let res = cvt(clone3(args_ptr, args_size));
+            match res {
+                Ok(n) => return Ok((n as pid_t, pidfd)),
+                Err(e) => match e.raw_os_error() {
+                    // Multiple threads can race to execute this store,
+                    // but that's fine - that just means that multiple threads
+                    // will have tried and failed to execute the same syscall,
+                    // with no other side effects.
+                    Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed),
+                    // Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
+                    Some(libc::EPERM) => {}
+                    _ => return Err(e),
+                },
+            }
+        }
+
+        // If we get here, the 'clone3' syscall does not exist
+        // or we do not have permission to call it
+        cvt(libc::fork()).map(|res| (res, pidfd))
+    }
+
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         let envp = self.capture_env();
 
@@ -308,6 +401,7 @@ impl Command {
             || (self.env_saw_path() && !self.program_is_path())
             || !self.get_closures().is_empty()
             || self.get_groups().is_some()
+            || self.get_create_pidfd()
         {
             return Ok(None);
         }
@@ -352,7 +446,7 @@ impl Command {
             None => None,
         };
 
-        let mut p = Process { pid: 0, status: None };
+        let mut p = Process::new(0, -1);
 
         struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
 
@@ -441,9 +535,27 @@ impl Command {
 pub struct Process {
     pid: pid_t,
     status: Option<ExitStatus>,
+    // On Linux, stores the pidfd created for this child.
+    // This is None if the user did not request pidfd creation,
+    // or if the pidfd could not be created for some reason
+    // (e.g. the `clone3` syscall was not available).
+    #[cfg(target_os = "linux")]
+    pidfd: Option<PidFd>,
 }
 
 impl Process {
+    #[cfg(target_os = "linux")]
+    fn new(pid: pid_t, pidfd: pid_t) -> Self {
+        use crate::sys_common::FromInner;
+        let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::new(pidfd)));
+        Process { pid, status: None, pidfd }
+    }
+
+    #[cfg(not(target_os = "linux"))]
+    fn new(pid: pid_t, _pidfd: pid_t) -> Self {
+        Process { pid, status: None }
+    }
+
     pub fn id(&self) -> u32 {
         self.pid as u32
     }
@@ -580,6 +692,24 @@ impl ExitStatusError {
     }
 }
 
+#[cfg(target_os = "linux")]
+#[unstable(feature = "linux_pidfd", issue = "82971")]
+impl crate::os::linux::process::ChildExt for crate::process::Child {
+    fn pidfd(&self) -> io::Result<&PidFd> {
+        self.handle
+            .pidfd
+            .as_ref()
+            .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created."))
+    }
+
+    fn take_pidfd(&mut self) -> io::Result<PidFd> {
+        self.handle
+            .pidfd
+            .take()
+            .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created."))
+    }
+}
+
 #[cfg(test)]
 #[path = "process_unix/tests.rs"]
 mod tests;
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index cad8be6d289..ba432ec5494 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -26,8 +26,6 @@ use crate::marker;
 use crate::mem;
 use crate::sync::atomic::{self, AtomicUsize, Ordering};
 
-// Temporary null documentation to work around #57569 until the fix is beta
-#[cfg_attr(bootstrap, doc = "")]
 pub(crate) macro weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
         #[allow(non_upper_case_globals)]
@@ -103,8 +101,6 @@ unsafe fn fetch(name: &str) -> usize {
     libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
 }
 
-// Temporary null documentation to work around #57569 until the fix is beta
-#[cfg_attr(bootstrap, doc = "")]
 #[cfg(not(any(target_os = "linux", target_os = "android")))]
 pub(crate) macro syscall {
     (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
@@ -123,7 +119,6 @@ pub(crate) macro syscall {
     )
 }
 
-#[cfg_attr(bootstrap, doc = "")]
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub(crate) macro syscall {
     (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index 4e6c301d29f..a06b44e96a9 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -4,8 +4,6 @@ pub mod memchr {
     pub use core::slice::memchr::{memchr, memrchr};
 }
 
-pub use crate::sys_common::os_str_bytes as os_str;
-
 // This is not necessarily correct. May want to consider making it part of the
 // spec definition?
 use crate::os::raw::c_char;
diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs
index 3ef4c6b8a8f..a1276193bda 100644
--- a/library/std/src/sys/unsupported/mod.rs
+++ b/library/std/src/sys/unsupported/mod.rs
@@ -11,6 +11,8 @@ pub mod io;
 pub mod mutex;
 pub mod net;
 pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
 #[path = "../unix/path.rs"]
 pub mod path;
 pub mod pipe;
diff --git a/library/std/src/sys/unsupported/os.rs b/library/std/src/sys/unsupported/os.rs
index e30395a0b1d..2886ec1180e 100644
--- a/library/std/src/sys/unsupported/os.rs
+++ b/library/std/src/sys/unsupported/os.rs
@@ -76,8 +76,8 @@ pub fn env() -> Env {
     panic!("not supported on this platform")
 }
 
-pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
-    Ok(None)
+pub fn getenv(_: &OsStr) -> Option<OsString> {
+    None
 }
 
 pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 4af99bfa464..8d62335aae5 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -32,7 +32,8 @@ pub mod io;
 pub mod mutex;
 pub mod net;
 pub mod os;
-pub use crate::sys_common::os_str_bytes as os_str;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
 #[path = "../unix/path.rs"]
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs
index f129ee55a83..c5229a18834 100644
--- a/library/std/src/sys/wasi/os.rs
+++ b/library/std/src/sys/wasi/os.rs
@@ -175,17 +175,16 @@ pub fn env() -> Env {
     }
 }
 
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    let k = CString::new(k.as_bytes())?;
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    let k = CString::new(k.as_bytes()).ok()?;
     unsafe {
         let _guard = env_lock();
         let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
-        let ret = if s.is_null() {
+        if s.is_null() {
             None
         } else {
             Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
-        };
-        Ok(ret)
+        }
     }
 }
 
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index cd701a333f8..c81d653a5e3 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -30,6 +30,8 @@ pub mod io;
 pub mod net;
 #[path = "../unsupported/os.rs"]
 pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
 #[path = "../unix/path.rs"]
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
@@ -45,8 +47,6 @@ pub mod thread_local_key;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
-pub use crate::sys_common::os_str_bytes as os_str;
-
 cfg_if::cfg_if! {
     if #[cfg(target_feature = "atomics")] {
         #[path = "atomics/condvar.rs"]
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index 77c378a66af..8db97ba50a8 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -253,22 +253,13 @@ pub fn chdir(p: &path::Path) -> io::Result<()> {
     cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop)
 }
 
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    let k = to_u16s(k)?;
-    let res = super::fill_utf16_buf(
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    let k = to_u16s(k).ok()?;
+    super::fill_utf16_buf(
         |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
         |buf| OsStringExt::from_wide(buf),
-    );
-    match res {
-        Ok(value) => Ok(Some(value)),
-        Err(e) => {
-            if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) {
-                Ok(None)
-            } else {
-                Err(e)
-            }
-        }
-    }
+    )
+    .ok()
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index db83bad60d8..894440564b7 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -26,10 +26,6 @@ pub mod fs;
 pub mod io;
 pub mod memchr;
 pub mod mutex;
-// `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows
-// when generating documentation.
-#[cfg(any(doc, not(windows)))]
-pub mod os_str_bytes;
 pub mod process;
 pub mod remutex;
 #[macro_use]