diff options
| -rw-r--r-- | src/tools/miri/src/lib.rs | 1 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/unix/foreign_items.rs | 2 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/unix/fs.rs | 68 |
3 files changed, 41 insertions, 30 deletions
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 479353bb983..97271c33a2e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -9,6 +9,7 @@ #![feature(is_some_and)] #![feature(nonzero_ops)] #![feature(local_key_cell_methods)] +#![feature(is_terminal)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index c21e0441cac..44a433df1e9 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "isatty" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.isatty(fd)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "pthread_atfork" => { let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index ed68976773d..0610f65db11 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -4,7 +4,7 @@ use std::convert::TryInto; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; -use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; +use std::io::{self, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::time::SystemTime; @@ -65,6 +65,8 @@ trait FileDescriptor: std::fmt::Debug { fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>; + fn is_tty(&self) -> bool; + #[cfg(unix)] fn as_unix_host_fd(&self) -> Option<i32> { None @@ -143,6 +145,10 @@ impl FileDescriptor for FileHandle { use std::os::unix::io::AsRawFd; Some(self.file.as_raw_fd()) } + + fn is_tty(&self) -> bool { + self.file.is_terminal() + } } impl FileDescriptor for io::Stdin { @@ -170,6 +176,10 @@ impl FileDescriptor for io::Stdin { fn as_unix_host_fd(&self) -> Option<i32> { Some(libc::STDIN_FILENO) } + + fn is_tty(&self) -> bool { + self.is_terminal() + } } impl FileDescriptor for io::Stdout { @@ -202,6 +212,10 @@ impl FileDescriptor for io::Stdout { fn as_unix_host_fd(&self) -> Option<i32> { Some(libc::STDOUT_FILENO) } + + fn is_tty(&self) -> bool { + self.is_terminal() + } } impl FileDescriptor for io::Stderr { @@ -227,12 +241,16 @@ impl FileDescriptor for io::Stderr { fn as_unix_host_fd(&self) -> Option<i32> { Some(libc::STDERR_FILENO) } + + fn is_tty(&self) -> bool { + self.is_terminal() + } } #[derive(Debug)] -struct DummyOutput; +struct NullOutput; -impl FileDescriptor for DummyOutput { +impl FileDescriptor for NullOutput { fn name(&self) -> &'static str { "stderr and stdout" } @@ -247,7 +265,11 @@ impl FileDescriptor for DummyOutput { } fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(DummyOutput)) + Ok(Box::new(NullOutput)) + } + + fn is_tty(&self) -> bool { + false } } @@ -267,8 +289,8 @@ impl FileHandler { let mut handles: BTreeMap<_, Box<dyn FileDescriptor>> = BTreeMap::new(); handles.insert(0i32, Box::new(io::stdin())); if mute_stdout_stderr { - handles.insert(1i32, Box::new(DummyOutput)); - handles.insert(2i32, Box::new(DummyOutput)); + handles.insert(1i32, Box::new(NullOutput)); + handles.insert(2i32, Box::new(NullOutput)); } else { handles.insert(1i32, Box::new(io::stdout())); handles.insert(2i32, Box::new(io::stderr())); @@ -1662,35 +1684,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } #[cfg_attr(not(unix), allow(unused))] - fn isatty(&mut self, miri_fd: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn isatty( + &mut self, + miri_fd: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); - #[cfg(unix)] + // "returns 1 if fd is an open file descriptor referring to a terminal; + // otherwise 0 is returned, and errno is set to indicate the error" if matches!(this.machine.isolated_op, IsolatedOp::Allow) { - let miri_fd = this.read_scalar(miri_fd)?.to_i32()?; - if let Some(host_fd) = - this.machine.file_handler.handles.get(&miri_fd).and_then(|fd| fd.as_unix_host_fd()) - { - // "returns 1 if fd is an open file descriptor referring to a terminal; - // otherwise 0 is returned, and errno is set to indicate the error" - // SAFETY: isatty has no preconditions - let is_tty = unsafe { libc::isatty(host_fd) }; - if is_tty == 0 { - let errno = std::io::Error::last_os_error() - .raw_os_error() - .map(Scalar::from_i32) - .unwrap(); - this.set_last_error(errno)?; - } - return Ok(is_tty); + let fd = this.read_scalar(miri_fd)?.to_i32()?; + if this.machine.file_handler.handles.get(&fd).map(|fd| fd.is_tty()) == Some(true) { + return Ok(Scalar::from_i32(1)); } } - // We are attemping to use a Unix interface on a non-Unix platform, or we are on a Unix - // platform and the passed file descriptor is not open, or isolation is enabled - // FIXME: It should be possible to emulate this at least on Windows by using - // GetConsoleMode. + // Fallback when the FD was not found or isolation is enabled. let enotty = this.eval_libc("ENOTTY")?; this.set_last_error(enotty)?; - Ok(0) + Ok(Scalar::from_i32(0)) } fn realpath( |
