From 4d4855c7620696fa4e0e1d8171385b69912e02a8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Apr 2022 13:12:55 +0000 Subject: [PATCH 1/6] Add a command line flag to avoid printing to stdout and stderr --- src/bin/miri.rs | 3 ++ src/eval.rs | 4 +++ src/machine.rs | 4 +-- src/shims/posix/fs.rs | 60 +++++++++++++++++++++++++++++++---- tests/run-pass/hide_stdout.rs | 5 +++ 5 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/hide_stdout.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e4d0af431312..b55b6f8d5589 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -374,6 +374,9 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } + "-Zmiri-drop-stdout-stderr" => { + miri_config.drop_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..f1cbb00942bb 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 drop_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, + drop_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index c0f833f17610..1fdc398dd9f0 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 @@ -327,7 +327,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.drop_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 73e21dd57dc4..78d0e958e2a0 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 DevNull; + +impl FileDescriptor for DevNull { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("/dev/null 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 /dev/null"); + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { + // We just don't write anything + Ok(Ok(bytes.len())) + } + + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on /dev/null"); + } + + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("/dev/null cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(DevNull)) + } +} + #[derive(Debug)] pub struct FileHandler { handles: BTreeMap>, } -impl<'tcx> Default for FileHandler { - fn default() -> Self { +impl<'tcx> FileHandler { + pub(crate) fn new(drop_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 drop_stdout_stderr { + handles.insert(0i32, Box::new(DevNull)); + handles.insert(1i32, Box::new(DevNull)); + } 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/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs new file mode 100644 index 000000000000..04a4ef9df174 --- /dev/null +++ b/tests/run-pass/hide_stdout.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-drop-stdout-stderr + +fn main() { + println!("cake"); +} From 1d0fe1b6bbf373190465f115777a2d98bb2741bd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Apr 2022 14:22:55 +0000 Subject: [PATCH 2/6] Implement the output dropping for windows, too --- src/machine.rs | 4 ++++ src/shims/windows/dlsym.rs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 1fdc398dd9f0..6cce1a5db252 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -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-drop-stdout-stderr and doesn't write the output but acts as if it succeeded. + pub(crate) drop_stdout_stderr: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -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, + drop_stdout_stderr: config.drop_stdout_stderr, } } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ac9e085b5d7c..05230531d917 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.drop_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { io::stdout().write(buf_cont) } else { io::stderr().write(buf_cont) From a192a199a8761a8c2b71ba2ca8202091b248716e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 26 Apr 2022 09:33:20 +0000 Subject: [PATCH 3/6] Rename flag, datastructure and messaging around muting stdout and stderr --- src/bin/miri.rs | 4 ++-- src/eval.rs | 4 ++-- src/machine.rs | 8 ++++---- src/shims/posix/fs.rs | 24 ++++++++++++------------ src/shims/windows/dlsym.rs | 2 +- tests/run-pass/hide_stdout.rs | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b55b6f8d5589..2fa045b57462 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -374,8 +374,8 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } - "-Zmiri-drop-stdout-stderr" => { - miri_config.drop_stdout_stderr = true; + "-Zmiri-mute-stdout-stderr" => { + miri_config.mute_stdout_stderr = true; } "-Zmiri-track-raw-pointers" => { eprintln!( diff --git a/src/eval.rs b/src/eval.rs index f1cbb00942bb..028c9b97abb3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -118,7 +118,7 @@ pub struct MiriConfig { 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 drop_stdout_stderr: bool, + pub mute_stdout_stderr: bool, } impl Default for MiriConfig { @@ -145,7 +145,7 @@ impl Default for MiriConfig { panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, strict_provenance: false, - drop_stdout_stderr: false, + mute_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index 6cce1a5db252..1c916220c8c5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -292,8 +292,8 @@ 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-drop-stdout-stderr and doesn't write the output but acts as if it succeeded. - pub(crate) drop_stdout_stderr: bool, + /// 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> { @@ -330,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: FileHandler::new(config.drop_stdout_stderr), + file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, @@ -347,7 +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, - drop_stdout_stderr: config.drop_stdout_stderr, + mute_stdout_stderr: config.mute_stdout_stderr, } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 78d0e958e2a0..1b0a94e0ffc9 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -252,11 +252,11 @@ impl FileDescriptor for io::Stderr { } #[derive(Debug)] -struct DevNull; +struct DummyOutput; -impl FileDescriptor for DevNull { +impl FileDescriptor for DummyOutput { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("/dev/null cannot be used as FileHandle"); + throw_unsup_format!("stderr and stdout cannot be used as FileHandle"); } fn read<'tcx>( @@ -264,7 +264,7 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, _bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from /dev/null"); + throw_unsup_format!("cannot read from stderr or stdout"); } fn write<'tcx>( @@ -272,7 +272,7 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { - // We just don't write anything + // We just don't write anything, but report to the user that we did. Ok(Ok(bytes.len())) } @@ -281,18 +281,18 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, _offset: SeekFrom, ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on /dev/null"); + throw_unsup_format!("cannot seek on stderr or stdout"); } fn close<'tcx>( self: Box, _communicate_allowed: bool, ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("/dev/null cannot be closed"); + throw_unsup_format!("stderr and stdout cannot be closed"); } fn dup<'tcx>(&mut self) -> io::Result> { - Ok(Box::new(DevNull)) + Ok(Box::new(DummyOutput)) } } @@ -302,11 +302,11 @@ pub struct FileHandler { } impl<'tcx> FileHandler { - pub(crate) fn new(drop_stdout_stderr: bool) -> FileHandler { + pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); - if drop_stdout_stderr { - handles.insert(0i32, Box::new(DevNull)); - handles.insert(1i32, Box::new(DevNull)); + 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())); diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 05230531d917..ddbad8c5affa 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -75,7 +75,7 @@ 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 this.machine.drop_stdout_stderr { + let res = if this.machine.mute_stdout_stderr { Ok(buf_cont.len()) } else if handle == -11 { io::stdout().write(buf_cont) diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs index 04a4ef9df174..849fce913862 100644 --- a/tests/run-pass/hide_stdout.rs +++ b/tests/run-pass/hide_stdout.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-drop-stdout-stderr +// compile-flags: -Zmiri-mute-stdout-stderr fn main() { println!("cake"); From 5e26cdaf3a574efa8e88b31b9df4d120e0805d7d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 26 Apr 2022 09:36:02 +0000 Subject: [PATCH 4/6] Add readme entry --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ca14f02d86ae..4cb03ed7b0b2 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,10 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. +* `-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 messages, but only want to see miri's + errors and warnings. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, and `warn-nobacktrace` are the supported actions. The default is to `abort`, From c8b947a5edb209c55c2ec2d6c4c1075db5d4d4ce Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 07:23:03 +0000 Subject: [PATCH 5/6] Use alphabetical order for miri flags --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4cb03ed7b0b2..291c01dd4cfd 100644 --- a/README.md +++ b/README.md @@ -265,10 +265,6 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. -* `-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 messages, but only want to see miri's - errors and warnings. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, and `warn-nobacktrace` are the supported actions. The default is to `abort`, @@ -290,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 messages, 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 From 6dc6256413a242a3917b01ac28059024dc6bef45 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 07:23:50 +0000 Subject: [PATCH 6/6] Wording nit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 291c01dd4cfd..127206e11544 100644 --- a/README.md +++ b/README.md @@ -288,7 +288,7 @@ environment variable: 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 messages, but only want to see miri's + 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