Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a command line flag to avoid printing to stdout and stderr #2084

Merged
merged 6 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<name>`, 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
Expand Down
3 changes: 3 additions & 0 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,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."
Expand Down
4 changes: 4 additions & 0 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -142,6 +145,7 @@ impl Default for MiriConfig {
panic_on_unsupported: false,
backtrace_style: BacktraceStyle::Short,
strict_provenance: false,
mute_stdout_stderr: false,
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
}
}

Expand Down
60 changes: 54 additions & 6 deletions src/shims/posix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<usize>> {
throw_unsup_format!("cannot read from stderr or stdout");
}

fn write<'tcx>(
&self,
_communicate_allowed: bool,
bytes: &[u8],
) -> InterpResult<'tcx, io::Result<usize>> {
// 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<u64>> {
throw_unsup_format!("cannot seek on stderr or stdout");
}

fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
throw_unsup_format!("stderr and stdout cannot be closed");
}

fn dup<'tcx>(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(DummyOutput))
}
}

#[derive(Debug)]
pub struct FileHandler {
handles: BTreeMap<i32, Box<dyn FileDescriptor>>,
}

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<dyn FileDescriptor>> = 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<dyn FileDescriptor>) -> i32 {
self.insert_fd_with_min_fd(file_handle, 0)
}
Expand Down
4 changes: 3 additions & 1 deletion src/shims/windows/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions tests/run-pass/hide_stdout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// compile-flags: -Zmiri-mute-stdout-stderr

fn main() {
println!("cake");
}