about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2020-09-27 00:00:00 +0000
committerTomasz Miąsko <tomasz.miasko@gmail.com>2020-09-27 22:55:43 +0200
commit7d98d2207a20d95e731bfc742d89389a67d6618d (patch)
treebbb180c48bcdb048cd38e9ae2ae2a4b6e736da29 /src
parent4529af972e55f8f85afaada0ee2dd18ab8653637 (diff)
Reopen standard streams when they are closed on Unix
The syscalls returning a new file descriptors generally use
lowest-numbered file descriptor not currently opened, without any
exceptions for those corresponding to the standard streams.

Previously when any of standard streams has been closed before starting
the application, operations on std::io::{stderr,stdin,stdout} objects
were likely to operate on other logically unrelated file resources
opened afterwards.

Avoid the issue by reopening the standard streams when they are closed.
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/no-stdio.rs22
1 files changed, 20 insertions, 2 deletions
diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs
index e72b7b26e22..1b0ad930da6 100644
--- a/src/test/ui/no-stdio.rs
+++ b/src/test/ui/no-stdio.rs
@@ -36,6 +36,16 @@ unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
     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;
@@ -77,10 +87,18 @@ unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> 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
     }
 
@@ -109,12 +127,12 @@ fn main() {
                         .stdout(Stdio::null())
                         .stderr(Stdio::null())
                         .status().unwrap();
-    assert!(status.success(), "{:?} isn't a success", status);
+    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);
+    assert!(status.success(), "{} isn't a success", status);
 }