about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJiahao XU <Jiahao_XU@outlook.com>2024-06-30 18:23:07 +1000
committerJiahao XU <Jiahao_XU@outlook.com>2024-07-23 23:13:56 +1000
commitc9c8a14884c19e51a0eee54ccd98efa7f0f2bddd (patch)
tree1b94b0d4990f0771508383ea979d012270473e53
parent52f3c71c8dc4aaed71e3035995fcbdd6d78c98c6 (diff)
downloadrust-c9c8a14884c19e51a0eee54ccd98efa7f0f2bddd.tar.gz
rust-c9c8a14884c19e51a0eee54ccd98efa7f0f2bddd.zip
Initial implementation of anonymous_pipe
Co-authored-by: Alphyr <47725341+a1phyr@users.noreply.github.com>
Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com>
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
-rw-r--r--library/std/Cargo.toml56
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/pipe.rs130
-rw-r--r--library/std/src/sys/anonymous_pipe/mod.rs18
-rw-r--r--library/std/src/sys/anonymous_pipe/tests.rs20
-rw-r--r--library/std/src/sys/anonymous_pipe/unix.rs103
-rw-r--r--library/std/src/sys/anonymous_pipe/unsupported.rs26
-rw-r--r--library/std/src/sys/anonymous_pipe/windows.rs109
-rw-r--r--library/std/src/sys/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/fd.rs5
-rw-r--r--library/std/src/sys/pal/unix/pipe.rs9
-rw-r--r--library/std/src/sys/pal/unsupported/pipe.rs15
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt1
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs1
-rw-r--r--library/std/src/sys/pal/windows/handle.rs7
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs24
-rw-r--r--library/std/tests/pipe_subprocess.rs39
17 files changed, 551 insertions, 16 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index b991b1cf22d..321d73b76a1 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -20,8 +20,12 @@ core = { path = "../core", public = true }
 compiler_builtins = { version = "0.1.105" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
-hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] }
-std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.14", default-features = false, features = [
+    'rustc-dep-of-std',
+] }
+std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [
+    'rustc-dep-of-std',
+] }
 
 # Dependencies of the `backtrace` crate
 rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
@@ -31,13 +35,27 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
+libc = { version = "0.2.153", default-features = false, features = [
+    'rustc-dep-of-std',
+], public = true }
 
 [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
-object = { version = "0.36.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }
+object = { version = "0.36.0", default-features = false, optional = true, features = [
+    'read_core',
+    'elf',
+    'macho',
+    'pe',
+    'unaligned',
+    'archive',
+] }
 
 [target.'cfg(target_os = "aix")'.dependencies]
-object = { version = "0.36.0", default-features = false, optional = true, features = ['read_core', 'xcoff', 'unaligned', 'archive'] }
+object = { version = "0.36.0", default-features = false, optional = true, features = [
+    'read_core',
+    'xcoff',
+    'unaligned',
+    'archive',
+] }
 
 [dev-dependencies]
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
@@ -47,13 +65,19 @@ rand_xorshift = "0.3.0"
 dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] }
 
 [target.x86_64-fortanix-unknown-sgx.dependencies]
-fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true }
+fortanix-sgx-abi = { version = "0.5.0", features = [
+    'rustc-dep-of-std',
+], public = true }
 
 [target.'cfg(target_os = "hermit")'.dependencies]
-hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true }
+hermit-abi = { version = "0.4.0", features = [
+    'rustc-dep-of-std',
+], public = true }
 
 [target.'cfg(target_os = "wasi")'.dependencies]
-wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
+wasi = { version = "0.11.0", features = [
+    'rustc-dep-of-std',
+], default-features = false }
 
 [target.'cfg(target_os = "uefi")'.dependencies]
 r-efi = { version = "4.2.0", features = ['rustc-dep-of-std'] }
@@ -61,9 +85,9 @@ r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] }
 
 [features]
 backtrace = [
-  'addr2line/rustc-dep-of-std',
-  'object/rustc-dep-of-std',
-  'miniz_oxide/rustc-dep-of-std',
+    'addr2line/rustc-dep-of-std',
+    'object/rustc-dep-of-std',
+    'miniz_oxide/rustc-dep-of-std',
 ]
 
 panic-unwind = ["panic_unwind"]
@@ -77,7 +101,10 @@ llvm-libunwind = ["unwind/llvm-libunwind"]
 system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
 
 # Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = ["core/panic_immediate_abort", "alloc/panic_immediate_abort"]
+panic_immediate_abort = [
+    "core/panic_immediate_abort",
+    "alloc/panic_immediate_abort",
+]
 # Choose algorithms that are optimized for binary size instead of runtime performance
 optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]
 
@@ -97,6 +124,11 @@ threads = 125
 # Maximum heap size
 heap_size = 0x8000000
 
+[[test]]
+name = "pipe-subprocess"
+path = "tests/pipe_subprocess.rs"
+harness = false
+
 [[bench]]
 name = "stdbenches"
 path = "benches/lib.rs"
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f0a73a308a4..0fd2edc21ac 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -590,6 +590,8 @@ pub mod panic;
 #[unstable(feature = "core_pattern_types", issue = "none")]
 pub mod pat;
 pub mod path;
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+pub mod pipe;
 pub mod process;
 pub mod sync;
 pub mod time;
diff --git a/library/std/src/pipe.rs b/library/std/src/pipe.rs
new file mode 100644
index 00000000000..f251b57a7cc
--- /dev/null
+++ b/library/std/src/pipe.rs
@@ -0,0 +1,130 @@
+//! Module for anonymous pipe
+//!
+//! ```
+//! #![feature(anonymous_pipe)]
+//!
+//! # #[cfg(miri)] fn main() {}
+//! # #[cfg(not(miri))]
+//! # fn main() -> std::io::Result<()> {
+//! let (reader, writer) = std::pipe::pipe()?;
+//! # Ok(())
+//! # }
+//! ```
+
+use crate::{
+    io,
+    sys::anonymous_pipe::{pipe as pipe_inner, AnonPipe},
+};
+
+/// Create anonymous pipe that is close-on-exec and blocking.
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+#[inline]
+pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
+    pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
+}
+
+/// Read end of the anonymous pipe.
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+#[derive(Debug)]
+pub struct PipeReader(pub(crate) AnonPipe);
+
+/// Write end of the anonymous pipe.
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+#[derive(Debug)]
+pub struct PipeWriter(pub(crate) AnonPipe);
+
+impl PipeReader {
+    /// Create a new [`PipeReader`] instance that shares the same underlying file description.
+    #[unstable(feature = "anonymous_pipe", issue = "127154")]
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.0.try_clone().map(Self)
+    }
+}
+
+impl PipeWriter {
+    /// Create a new [`PipeWriter`] instance that shares the same underlying file description.
+    #[unstable(feature = "anonymous_pipe", issue = "127154")]
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.0.try_clone().map(Self)
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Read for &PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+    fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Read for PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+    fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Write for &PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+
+    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Write for PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+
+    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+}
diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs
new file mode 100644
index 00000000000..74875677cf3
--- /dev/null
+++ b/library/std/src/sys/anonymous_pipe/mod.rs
@@ -0,0 +1,18 @@
+cfg_if::cfg_if! {
+    if #[cfg(unix)] {
+        mod unix;
+        pub(crate) use unix::{AnonPipe, pipe};
+
+        #[cfg(all(test, not(miri)))]
+        mod tests;
+    } else if #[cfg(windows)] {
+        mod windows;
+        pub(crate) use windows::{AnonPipe, pipe};
+
+        #[cfg(all(test, not(miri)))]
+        mod tests;
+    } else {
+        mod unsupported;
+        pub(crate) use unsupported::{AnonPipe, pipe};
+    }
+}
diff --git a/library/std/src/sys/anonymous_pipe/tests.rs b/library/std/src/sys/anonymous_pipe/tests.rs
new file mode 100644
index 00000000000..f5ea583eefe
--- /dev/null
+++ b/library/std/src/sys/anonymous_pipe/tests.rs
@@ -0,0 +1,20 @@
+use crate::{
+    io::{Read, Write},
+    pipe::pipe,
+};
+
+#[test]
+fn pipe_creation_clone_and_rw() {
+    let (rx, tx) = pipe().unwrap();
+
+    tx.try_clone().unwrap().write_all(b"12345").unwrap();
+    drop(tx);
+
+    let mut rx2 = rx.try_clone().unwrap();
+    drop(rx);
+
+    let mut s = String::new();
+    rx2.read_to_string(&mut s).unwrap();
+    drop(rx2);
+    assert_eq!(s, "12345");
+}
diff --git a/library/std/src/sys/anonymous_pipe/unix.rs b/library/std/src/sys/anonymous_pipe/unix.rs
new file mode 100644
index 00000000000..ddbf1d7334f
--- /dev/null
+++ b/library/std/src/sys/anonymous_pipe/unix.rs
@@ -0,0 +1,103 @@
+use crate::{
+    io,
+    os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd},
+    pipe::{PipeReader, PipeWriter},
+    process::Stdio,
+    sys::{fd::FileDesc, pipe::anon_pipe},
+    sys_common::{FromInner, IntoInner},
+};
+
+pub(crate) type AnonPipe = FileDesc;
+
+#[inline]
+pub(crate) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner()))
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsFd for PipeReader {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsRawFd for PipeReader {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeReader> for OwnedFd {
+    fn from(pipe: PipeReader) -> Self {
+        FileDesc::into_inner(pipe.0)
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl FromRawFd for PipeReader {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FileDesc::from_raw_fd(raw_fd))
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl IntoRawFd for PipeReader {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeReader> for Stdio {
+    fn from(pipe: PipeReader) -> Self {
+        Self::from(OwnedFd::from(pipe))
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsFd for PipeWriter {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsRawFd for PipeWriter {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeWriter> for OwnedFd {
+    fn from(pipe: PipeWriter) -> Self {
+        FileDesc::into_inner(pipe.0)
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl FromRawFd for PipeWriter {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FileDesc::from_raw_fd(raw_fd))
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl IntoRawFd for PipeWriter {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeWriter> for Stdio {
+    fn from(pipe: PipeWriter) -> Self {
+        Self::from(OwnedFd::from(pipe))
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<OwnedFd> for PipeReader {
+    fn from(owned_fd: OwnedFd) -> Self {
+        Self(FileDesc::from_inner(owned_fd))
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<OwnedFd> for PipeWriter {
+    fn from(owned_fd: OwnedFd) -> Self {
+        Self(FileDesc::from_inner(owned_fd))
+    }
+}
diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs
new file mode 100644
index 00000000000..5962b69203e
--- /dev/null
+++ b/library/std/src/sys/anonymous_pipe/unsupported.rs
@@ -0,0 +1,26 @@
+use crate::{
+    io,
+    pipe::{PipeReader, PipeWriter},
+    process::Stdio,
+};
+
+pub(crate) use crate::sys::pipe::AnonPipe;
+
+#[inline]
+pub(crate) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    Err(io::Error::UNSUPPORTED_PLATFORM)
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeReader> for Stdio {
+    fn from(pipe: PipeReader) -> Self {
+        pipe.0.diverge()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeWriter> for Stdio {
+    fn from(pipe: PipeWriter) -> Self {
+        pipe.0.diverge()
+    }
+}
diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/anonymous_pipe/windows.rs
new file mode 100644
index 00000000000..81f95aa286a
--- /dev/null
+++ b/library/std/src/sys/anonymous_pipe/windows.rs
@@ -0,0 +1,109 @@
+use crate::{
+    io,
+    os::windows::io::{
+        AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
+    },
+    pipe::{PipeReader, PipeWriter},
+    process::Stdio,
+    sys::{handle::Handle, pipe::unnamed_anon_pipe},
+    sys_common::{FromInner, IntoInner},
+};
+
+pub(crate) type AnonPipe = Handle;
+
+#[inline]
+pub(crate) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    unnamed_anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner()))
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsHandle for PipeReader {
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        self.0.as_handle()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsRawHandle for PipeReader {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.0.as_raw_handle()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl FromRawHandle for PipeReader {
+    unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
+        Self(Handle::from_raw_handle(raw_handle))
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl IntoRawHandle for PipeReader {
+    fn into_raw_handle(self) -> RawHandle {
+        self.0.into_raw_handle()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeReader> for OwnedHandle {
+    fn from(pipe: PipeReader) -> Self {
+        Handle::into_inner(pipe.0)
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeReader> for Stdio {
+    fn from(pipe: PipeReader) -> Self {
+        Self::from(OwnedHandle::from(pipe))
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsHandle for PipeWriter {
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        self.0.as_handle()
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl AsRawHandle for PipeWriter {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.0.as_raw_handle()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl FromRawHandle for PipeWriter {
+    unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
+        Self(Handle::from_raw_handle(raw_handle))
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl IntoRawHandle for PipeWriter {
+    fn into_raw_handle(self) -> RawHandle {
+        self.0.into_raw_handle()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeWriter> for OwnedHandle {
+    fn from(pipe: PipeWriter) -> Self {
+        Handle::into_inner(pipe.0)
+    }
+}
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<PipeWriter> for Stdio {
+    fn from(pipe: PipeWriter) -> Self {
+        Self::from(OwnedHandle::from(pipe))
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<OwnedHandle> for PipeReader {
+    fn from(owned_handle: OwnedHandle) -> Self {
+        Self(Handle::from_inner(owned_handle))
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl From<OwnedHandle> for PipeWriter {
+    fn from(owned_handle: OwnedHandle) -> Self {
+        Self(Handle::from_inner(owned_handle))
+    }
+}
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index e50758ce00d..202997b7495 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -7,6 +7,8 @@ mod pal;
 
 mod personality;
 
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+pub mod anonymous_pipe;
 pub mod backtrace;
 pub mod cmath;
 pub mod exit_guard;
diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs
index 1701717db59..10ae3c3ab57 100644
--- a/library/std/src/sys/pal/unix/fd.rs
+++ b/library/std/src/sys/pal/unix/fd.rs
@@ -82,6 +82,11 @@ const fn max_iov() -> usize {
 }
 
 impl FileDesc {
+    #[inline]
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.duplicate()
+    }
+
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::read(
diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs
index 33db24e77e4..8762af614f1 100644
--- a/library/std/src/sys/pal/unix/pipe.rs
+++ b/library/std/src/sys/pal/unix/pipe.rs
@@ -9,6 +9,7 @@ use crate::sys_common::{FromInner, IntoInner};
 // Anonymous pipes
 ////////////////////////////////////////////////////////////////////////////////
 
+#[derive(Debug)]
 pub struct AnonPipe(FileDesc);
 
 pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
@@ -46,6 +47,10 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
 }
 
 impl AnonPipe {
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.0.duplicate().map(Self)
+    }
+
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.0.read(buf)
     }
@@ -79,6 +84,10 @@ impl AnonPipe {
     pub fn is_write_vectored(&self) -> bool {
         self.0.is_write_vectored()
     }
+
+    pub fn as_file_desc(&self) -> &FileDesc {
+        &self.0
+    }
 }
 
 impl IntoInner<FileDesc> for AnonPipe {
diff --git a/library/std/src/sys/pal/unsupported/pipe.rs b/library/std/src/sys/pal/unsupported/pipe.rs
index d7d8f297ae5..781eafe2f1a 100644
--- a/library/std/src/sys/pal/unsupported/pipe.rs
+++ b/library/std/src/sys/pal/unsupported/pipe.rs
@@ -1,8 +1,21 @@
-use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::{
+    fmt,
+    io::{self, BorrowedCursor, IoSlice, IoSliceMut},
+};
 
 pub struct AnonPipe(!);
 
+impl fmt::Debug for AnonPipe {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
 impl AnonPipe {
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.0
+    }
+
     pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
         self.0
     }
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index 5ad4a3731d8..7423bbe7694 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2462,6 +2462,7 @@ Windows.Win32.System.LibraryLoader.GetProcAddress
 Windows.Win32.System.Performance.QueryPerformanceCounter
 Windows.Win32.System.Performance.QueryPerformanceFrequency
 Windows.Win32.System.Pipes.CreateNamedPipeW
+Windows.Win32.System.Pipes.CreatePipe
 Windows.Win32.System.Pipes.NAMED_PIPE_MODE
 Windows.Win32.System.Pipes.PIPE_ACCEPT_REMOTE_CLIENTS
 Windows.Win32.System.Pipes.PIPE_CLIENT_END
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index fea00fec9ae..91c7d7ebc5e 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -14,6 +14,7 @@ windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes
 windows_targets::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE);
 windows_targets::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn CreatePipe(hreadpipe : *mut HANDLE, hwritepipe : *mut HANDLE, lppipeattributes : *const SECURITY_ATTRIBUTES, nsize : u32) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> BOOLEAN);
 windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE);
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index aaa1831dcc2..706062ab984 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -17,6 +17,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 /// An owned container for `HANDLE` object, closing them on Drop.
 ///
 /// All methods are inherited through a `Deref` impl to `RawHandle`
+#[derive(Debug)]
 pub struct Handle(OwnedHandle);
 
 impl Handle {
@@ -136,6 +137,12 @@ impl Handle {
         }
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+
+        Read::read_to_end(&mut me, buf)
+    }
+
     pub unsafe fn read_overlapped(
         &self,
         buf: &mut [mem::MaybeUninit<u8>],
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 7a309b9638b..d5e2356116f 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -1,7 +1,7 @@
 use crate::os::windows::prelude::*;
 
 use crate::ffi::OsStr;
-use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::path::Path;
 use crate::ptr;
@@ -39,6 +39,23 @@ pub struct Pipes {
     pub theirs: AnonPipe,
 }
 
+/// Create true unnamed anonymous pipe.
+pub fn unnamed_anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    let mut read_pipe = c::INVALID_HANDLE_VALUE;
+    let mut write_pipe = c::INVALID_HANDLE_VALUE;
+
+    let ret = unsafe { c::CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) };
+
+    if ret == 0 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok((
+            AnonPipe::from_inner(unsafe { Handle::from_raw_handle(read_pipe) }),
+            AnonPipe::from_inner(unsafe { Handle::from_raw_handle(write_pipe) }),
+        ))
+    }
+}
+
 /// Although this looks similar to `anon_pipe` in the Unix module it's actually
 /// subtly different. Here we'll return two pipes in the `Pipes` return value,
 /// but one is intended for "us" where as the other is intended for "someone
@@ -181,7 +198,7 @@ pub fn spawn_pipe_relay(
     their_handle_inheritable: bool,
 ) -> io::Result<AnonPipe> {
     // We need this handle to live for the lifetime of the thread spawned below.
-    let source = source.duplicate()?;
+    let source = source.try_clone()?;
 
     // create a new pair of anon pipes.
     let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?;
@@ -237,7 +254,8 @@ impl AnonPipe {
     pub fn into_handle(self) -> Handle {
         self.inner
     }
-    fn duplicate(&self) -> io::Result<Self> {
+
+    pub fn try_clone(&self) -> io::Result<Self> {
         self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| AnonPipe { inner })
     }
 
diff --git a/library/std/tests/pipe_subprocess.rs b/library/std/tests/pipe_subprocess.rs
new file mode 100644
index 00000000000..c2278098b9b
--- /dev/null
+++ b/library/std/tests/pipe_subprocess.rs
@@ -0,0 +1,39 @@
+#![feature(anonymous_pipe)]
+
+fn main() {
+    #[cfg(all(not(miri), any(unix, windows)))]
+    {
+        use std::{env, io::Read, pipe::pipe, process};
+
+        if env::var("I_AM_THE_CHILD").is_ok() {
+            child();
+        } else {
+            parent();
+        }
+
+        fn parent() {
+            let me = env::current_exe().unwrap();
+
+            let (rx, tx) = pipe().unwrap();
+            assert!(
+                process::Command::new(me)
+                    .env("I_AM_THE_CHILD", "1")
+                    .stdout(tx)
+                    .status()
+                    .unwrap()
+                    .success()
+            );
+
+            let mut s = String::new();
+            (&rx).read_to_string(&mut s).unwrap();
+            drop(rx);
+            assert_eq!(s, "Heloo,\n");
+
+            println!("Test pipe_subprocess.rs success");
+        }
+
+        fn child() {
+            println!("Heloo,");
+        }
+    }
+}