summaryrefslogtreecommitdiffstats
path: root/src/test/ui/process/no-stdio.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/process/no-stdio.rs
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/process/no-stdio.rs')
-rw-r--r--src/test/ui/process/no-stdio.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/test/ui/process/no-stdio.rs b/src/test/ui/process/no-stdio.rs
new file mode 100644
index 000000000..24985386a
--- /dev/null
+++ b/src/test/ui/process/no-stdio.rs
@@ -0,0 +1,139 @@
+// run-pass
+// ignore-android
+// ignore-emscripten no processes
+// ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::process::{Command, Stdio};
+use std::env;
+use std::io::{self, Read, Write};
+
+#[cfg(unix)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+ let doit = |a| {
+ let r = libc::dup(a);
+ assert!(r >= 0);
+ return r
+ };
+ let a = doit(0);
+ let b = doit(1);
+ let c = doit(2);
+
+ assert!(libc::close(0) >= 0);
+ assert!(libc::close(1) >= 0);
+ assert!(libc::close(2) >= 0);
+
+ let r = f();
+
+ assert!(libc::dup2(a, 0) >= 0);
+ assert!(libc::dup2(b, 1) >= 0);
+ assert!(libc::dup2(c, 2) >= 0);
+
+ return r
+}
+
+#[cfg(unix)]
+fn assert_fd_is_valid(fd: libc::c_int) {
+ if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } {
+ panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error());
+ }
+}
+
+#[cfg(windows)]
+fn assert_fd_is_valid(_fd: libc::c_int) {}
+
+#[cfg(windows)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+ type DWORD = u32;
+ type HANDLE = *mut u8;
+ type BOOL = i32;
+
+ const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
+ const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+ const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
+ const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+
+ extern "system" {
+ fn GetStdHandle(which: DWORD) -> HANDLE;
+ fn SetStdHandle(which: DWORD, handle: HANDLE) -> BOOL;
+ }
+
+ let doit = |id| {
+ let handle = GetStdHandle(id);
+ assert!(handle != INVALID_HANDLE_VALUE);
+ assert!(SetStdHandle(id, INVALID_HANDLE_VALUE) != 0);
+ return handle
+ };
+
+ let a = doit(STD_INPUT_HANDLE);
+ let b = doit(STD_OUTPUT_HANDLE);
+ let c = doit(STD_ERROR_HANDLE);
+
+ let r = f();
+
+ let doit = |id, handle| {
+ assert!(SetStdHandle(id, handle) != 0);
+ };
+ doit(STD_INPUT_HANDLE, a);
+ doit(STD_OUTPUT_HANDLE, b);
+ doit(STD_ERROR_HANDLE, c);
+
+ return r
+}
+
+fn main() {
+ if env::args().len() > 1 {
+ // Writing to stdout & stderr should not panic.
+ println!("test");
+ assert!(io::stdout().write(b"test\n").is_ok());
+ assert!(io::stderr().write(b"test\n").is_ok());
+
+ // Stdin should be at EOF.
+ assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0);
+
+ // Standard file descriptors should be valid on UNIX:
+ assert_fd_is_valid(0);
+ assert_fd_is_valid(1);
+ assert_fd_is_valid(2);
+ return
+ }
+
+ // First, make sure reads/writes without stdio work if stdio itself is
+ // missing.
+ let (a, b, c) = unsafe {
+ without_stdio(|| {
+ let a = io::stdout().write(b"test\n");
+ let b = io::stderr().write(b"test\n");
+ let c = io::stdin().read(&mut [0; 10]);
+
+ (a, b, c)
+ })
+ };
+
+ assert_eq!(a.unwrap(), 5);
+ assert_eq!(b.unwrap(), 5);
+ assert_eq!(c.unwrap(), 0);
+
+ // Second, spawn a child and do some work with "null" descriptors to make
+ // sure it's ok
+ let me = env::current_exe().unwrap();
+ let status = Command::new(&me)
+ .arg("next")
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status().unwrap();
+ assert!(status.success(), "{} isn't a success", status);
+
+ // Finally, close everything then spawn a child to make sure everything is
+ // *still* ok.
+ let status = unsafe {
+ without_stdio(|| Command::new(&me).arg("next").status())
+ }.unwrap();
+ assert!(status.success(), "{} isn't a success", status);
+}