]> git.lizzy.rs Git - rust.git/blobdiff - library/std/src/process.rs
Rollup merge of #73955 - hellow554:unsafe_process, r=Mark-Simulacrum
[rust.git] / library / std / src / process.rs
index c42bc1096528b7266507ce755737bd5535e16234..00e2dbc9c1dbf33e5d3c7c94c36edf4b6635f762 100644 (file)
 //! [`Read`]: io::Read
 
 #![stable(feature = "process", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests;
 
 use crate::io::prelude::*;
 
@@ -318,7 +322,8 @@ fn is_read_vectored(&self) -> bool {
 
     #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 
@@ -378,7 +383,8 @@ fn is_read_vectored(&self) -> bool {
 
     #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 
@@ -1702,411 +1708,3 @@ fn report(self) -> i32 {
         self.0.as_i32()
     }
 }
-
-#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
-mod tests {
-    use crate::io::prelude::*;
-
-    use super::{Command, Output, Stdio};
-    use crate::io::ErrorKind;
-    use crate::str;
-
-    // FIXME(#10380) these tests should not all be ignored on android.
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn smoke() {
-        let p = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "exit 0"]).spawn()
-        } else {
-            Command::new("true").spawn()
-        };
-        assert!(p.is_ok());
-        let mut p = p.unwrap();
-        assert!(p.wait().unwrap().success());
-    }
-
-    #[test]
-    #[cfg_attr(target_os = "android", ignore)]
-    fn smoke_failure() {
-        match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
-            Ok(..) => panic!(),
-            Err(..) => {}
-        }
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn exit_reported_right() {
-        let p = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "exit 1"]).spawn()
-        } else {
-            Command::new("false").spawn()
-        };
-        assert!(p.is_ok());
-        let mut p = p.unwrap();
-        assert!(p.wait().unwrap().code() == Some(1));
-        drop(p.wait());
-    }
-
-    #[test]
-    #[cfg(unix)]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn signal_reported_right() {
-        use crate::os::unix::process::ExitStatusExt;
-
-        let mut p =
-            Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
-        p.kill().unwrap();
-        match p.wait().unwrap().signal() {
-            Some(9) => {}
-            result => panic!("not terminated by signal 9 (instead, {:?})", result),
-        }
-    }
-
-    pub fn run_output(mut cmd: Command) -> String {
-        let p = cmd.spawn();
-        assert!(p.is_ok());
-        let mut p = p.unwrap();
-        assert!(p.stdout.is_some());
-        let mut ret = String::new();
-        p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
-        assert!(p.wait().unwrap().success());
-        return ret;
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn stdout_works() {
-        if cfg!(target_os = "windows") {
-            let mut cmd = Command::new("cmd");
-            cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
-            assert_eq!(run_output(cmd), "foobar\r\n");
-        } else {
-            let mut cmd = Command::new("echo");
-            cmd.arg("foobar").stdout(Stdio::piped());
-            assert_eq!(run_output(cmd), "foobar\n");
-        }
-    }
-
-    #[test]
-    #[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
-    fn set_current_dir_works() {
-        let mut cmd = Command::new("/bin/sh");
-        cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
-        assert_eq!(run_output(cmd), "/\n");
-    }
-
-    #[test]
-    #[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
-    fn stdin_works() {
-        let mut p = Command::new("/bin/sh")
-            .arg("-c")
-            .arg("read line; echo $line")
-            .stdin(Stdio::piped())
-            .stdout(Stdio::piped())
-            .spawn()
-            .unwrap();
-        p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
-        drop(p.stdin.take());
-        let mut out = String::new();
-        p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
-        assert!(p.wait().unwrap().success());
-        assert_eq!(out, "foobar\n");
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn test_process_status() {
-        let mut status = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
-        } else {
-            Command::new("false").status().unwrap()
-        };
-        assert!(status.code() == Some(1));
-
-        status = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
-        } else {
-            Command::new("true").status().unwrap()
-        };
-        assert!(status.success());
-    }
-
-    #[test]
-    fn test_process_output_fail_to_start() {
-        match Command::new("/no-binary-by-this-name-should-exist").output() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
-            Ok(..) => panic!(),
-        }
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn test_process_output_output() {
-        let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
-        } else {
-            Command::new("echo").arg("hello").output().unwrap()
-        };
-        let output_str = str::from_utf8(&stdout).unwrap();
-
-        assert!(status.success());
-        assert_eq!(output_str.trim().to_string(), "hello");
-        assert_eq!(stderr, Vec::new());
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn test_process_output_error() {
-        let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
-        } else {
-            Command::new("mkdir").arg("./").output().unwrap()
-        };
-
-        assert!(status.code() == Some(1));
-        assert_eq!(stdout, Vec::new());
-        assert!(!stderr.is_empty());
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn test_finish_once() {
-        let mut prog = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
-        } else {
-            Command::new("false").spawn().unwrap()
-        };
-        assert!(prog.wait().unwrap().code() == Some(1));
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn test_finish_twice() {
-        let mut prog = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
-        } else {
-            Command::new("false").spawn().unwrap()
-        };
-        assert!(prog.wait().unwrap().code() == Some(1));
-        assert!(prog.wait().unwrap().code() == Some(1));
-    }
-
-    #[test]
-    #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
-    fn test_wait_with_output_once() {
-        let prog = if cfg!(target_os = "windows") {
-            Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
-        } else {
-            Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
-        };
-
-        let Output { status, stdout, stderr } = prog.wait_with_output().unwrap();
-        let output_str = str::from_utf8(&stdout).unwrap();
-
-        assert!(status.success());
-        assert_eq!(output_str.trim().to_string(), "hello");
-        assert_eq!(stderr, Vec::new());
-    }
-
-    #[cfg(all(unix, not(target_os = "android")))]
-    pub fn env_cmd() -> Command {
-        Command::new("env")
-    }
-    #[cfg(target_os = "android")]
-    pub fn env_cmd() -> Command {
-        let mut cmd = Command::new("/system/bin/sh");
-        cmd.arg("-c").arg("set");
-        cmd
-    }
-
-    #[cfg(windows)]
-    pub fn env_cmd() -> Command {
-        let mut cmd = Command::new("cmd");
-        cmd.arg("/c").arg("set");
-        cmd
-    }
-
-    #[test]
-    #[cfg_attr(target_os = "vxworks", ignore)]
-    fn test_override_env() {
-        use crate::env;
-
-        // In some build environments (such as chrooted Nix builds), `env` can
-        // only be found in the explicitly-provided PATH env variable, not in
-        // default places such as /bin or /usr/bin. So we need to pass through
-        // PATH to our sub-process.
-        let mut cmd = env_cmd();
-        cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
-        if let Some(p) = env::var_os("PATH") {
-            cmd.env("PATH", &p);
-        }
-        let result = cmd.output().unwrap();
-        let output = String::from_utf8_lossy(&result.stdout).to_string();
-
-        assert!(
-            output.contains("RUN_TEST_NEW_ENV=123"),
-            "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
-            output
-        );
-    }
-
-    #[test]
-    #[cfg_attr(target_os = "vxworks", ignore)]
-    fn test_add_to_env() {
-        let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
-        let output = String::from_utf8_lossy(&result.stdout).to_string();
-
-        assert!(
-            output.contains("RUN_TEST_NEW_ENV=123"),
-            "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
-            output
-        );
-    }
-
-    #[test]
-    #[cfg_attr(target_os = "vxworks", ignore)]
-    fn test_capture_env_at_spawn() {
-        use crate::env;
-
-        let mut cmd = env_cmd();
-        cmd.env("RUN_TEST_NEW_ENV1", "123");
-
-        // This variable will not be present if the environment has already
-        // been captured above.
-        env::set_var("RUN_TEST_NEW_ENV2", "456");
-        let result = cmd.output().unwrap();
-        env::remove_var("RUN_TEST_NEW_ENV2");
-
-        let output = String::from_utf8_lossy(&result.stdout).to_string();
-
-        assert!(
-            output.contains("RUN_TEST_NEW_ENV1=123"),
-            "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
-            output
-        );
-        assert!(
-            output.contains("RUN_TEST_NEW_ENV2=456"),
-            "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
-            output
-        );
-    }
-
-    // Regression tests for #30858.
-    #[test]
-    fn test_interior_nul_in_progname_is_error() {
-        match Command::new("has-some-\0\0s-inside").spawn() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
-            Ok(_) => panic!(),
-        }
-    }
-
-    #[test]
-    fn test_interior_nul_in_arg_is_error() {
-        match Command::new("echo").arg("has-some-\0\0s-inside").spawn() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
-            Ok(_) => panic!(),
-        }
-    }
-
-    #[test]
-    fn test_interior_nul_in_args_is_error() {
-        match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
-            Ok(_) => panic!(),
-        }
-    }
-
-    #[test]
-    fn test_interior_nul_in_current_dir_is_error() {
-        match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
-            Ok(_) => panic!(),
-        }
-    }
-
-    // Regression tests for #30862.
-    #[test]
-    #[cfg_attr(target_os = "vxworks", ignore)]
-    fn test_interior_nul_in_env_key_is_error() {
-        match env_cmd().env("has-some-\0\0s-inside", "value").spawn() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
-            Ok(_) => panic!(),
-        }
-    }
-
-    #[test]
-    #[cfg_attr(target_os = "vxworks", ignore)]
-    fn test_interior_nul_in_env_value_is_error() {
-        match env_cmd().env("key", "has-some-\0\0s-inside").spawn() {
-            Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
-            Ok(_) => panic!(),
-        }
-    }
-
-    /// Tests that process creation flags work by debugging a process.
-    /// Other creation flags make it hard or impossible to detect
-    /// behavioral changes in the process.
-    #[test]
-    #[cfg(windows)]
-    fn test_creation_flags() {
-        use crate::os::windows::process::CommandExt;
-        use crate::sys::c::{BOOL, DWORD, INFINITE};
-        #[repr(C, packed)]
-        struct DEBUG_EVENT {
-            pub event_code: DWORD,
-            pub process_id: DWORD,
-            pub thread_id: DWORD,
-            // This is a union in the real struct, but we don't
-            // need this data for the purposes of this test.
-            pub _junk: [u8; 164],
-        }
-
-        extern "system" {
-            fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
-            fn ContinueDebugEvent(
-                dwProcessId: DWORD,
-                dwThreadId: DWORD,
-                dwContinueStatus: DWORD,
-            ) -> BOOL;
-        }
-
-        const DEBUG_PROCESS: DWORD = 1;
-        const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
-        const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
-
-        let mut child = Command::new("cmd")
-            .creation_flags(DEBUG_PROCESS)
-            .stdin(Stdio::piped())
-            .spawn()
-            .unwrap();
-        child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
-        let mut events = 0;
-        let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] };
-        loop {
-            if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
-                panic!("WaitForDebugEvent failed!");
-            }
-            events += 1;
-
-            if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
-                break;
-            }
-
-            if unsafe {
-                ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED)
-            } == 0
-            {
-                panic!("ContinueDebugEvent failed!");
-            }
-        }
-        assert!(events > 0);
-    }
-
-    #[test]
-    fn test_command_implements_send_sync() {
-        fn take_send_sync_type<T: Send + Sync>(_: T) {}
-        take_send_sync_type(Command::new(""))
-    }
-}