Auto merge of #2084 - rust-lang:silence, r=RalfJung

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

This is practical for tests that don't actually care about the output and thus don't want it intermingled with miri's warnings, errors or ICEs

fixes #2083
This commit is contained in:
bors 2022-05-10 07:24:07 +00:00
commit 36c274aa38
7 changed files with 79 additions and 9 deletions

View file

@ -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

View file

@ -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."

View file

@ -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,
}
}
}

View file

@ -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,
}
}

View file

@ -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)
}

View file

@ -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)

View file

@ -0,0 +1,5 @@
// compile-flags: -Zmiri-mute-stdout-stderr
fn main() {
println!("cake");
}