diff --git a/README.md b/README.md index 9b05d3420e61..5b97ca95d93f 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,10 @@ environment variable: This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed using the tools in the repository https://github.com/rust-lang/measureme. +* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, + but reports to the program that it did actually write. This is useful when you + are not interested in the actual program's output, but only want to see miri's + errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated application instead of raising an error within the context of Miri (and halting diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3fac07a41a6b..b1c2872513e4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -384,6 +384,9 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } + "-Zmiri-mute-stdout-stderr" => { + miri_config.mute_stdout_stderr = true; + } "-Zmiri-track-raw-pointers" => { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." diff --git a/src/eval.rs b/src/eval.rs index f8d23cb8279c..028c9b97abb3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -116,6 +116,9 @@ pub struct MiriConfig { /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return /// pointers with an invalid provenance, i.e., not valid for any memory access. pub strict_provenance: bool, + /// Whether to ignore any output by the program. This is helpful when debugging miri + /// as its messages don't get intermingled with the program messages. + pub mute_stdout_stderr: bool, } impl Default for MiriConfig { @@ -142,6 +145,7 @@ impl Default for MiriConfig { panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, strict_provenance: false, + mute_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index 2d8f5855330f..1f1caa866118 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::*; +use crate::{*, shims::posix::FileHandler}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -291,6 +291,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 pub(crate) cmpxchg_weak_failure_rate: f64, + + /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. + pub(crate) mute_stdout_stderr: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -327,7 +330,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: config.validate, enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, - file_handler: Default::default(), + file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, @@ -344,6 +347,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, + mute_stdout_stderr: config.mute_stdout_stderr, } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a63b2ad80c27..dec1e9781680 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -251,22 +251,70 @@ impl FileDescriptor for io::Stderr { } } +#[derive(Debug)] +struct DummyOutput; + +impl FileDescriptor for DummyOutput { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stderr and stdout cannot be used as FileHandle"); + } + + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from stderr or stdout"); + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { + // We just don't write anything, but report to the user that we did. + Ok(Ok(bytes.len())) + } + + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stderr or stdout"); + } + + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stderr and stdout cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(DummyOutput)) + } +} + #[derive(Debug)] pub struct FileHandler { handles: BTreeMap>, } -impl<'tcx> Default for FileHandler { - fn default() -> Self { +impl<'tcx> FileHandler { + pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); - handles.insert(0i32, Box::new(io::stdin())); - handles.insert(1i32, Box::new(io::stdout())); + if mute_stdout_stderr { + handles.insert(0i32, Box::new(DummyOutput)); + handles.insert(1i32, Box::new(DummyOutput)); + } else { + handles.insert(0i32, Box::new(io::stdin())); + handles.insert(1i32, Box::new(io::stdout())); + } handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } } -} -impl<'tcx> FileHandler { fn insert_fd(&mut self, file_handle: Box) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 5583e3a25895..865c01386045 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -75,7 +75,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { + let res = if this.machine.mute_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { io::stdout().write(buf_cont) } else { io::stderr().write(buf_cont) diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs new file mode 100644 index 000000000000..849fce913862 --- /dev/null +++ b/tests/run-pass/hide_stdout.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-mute-stdout-stderr + +fn main() { + println!("cake"); +}