Skip to content

Commit f28165e

Browse files
committed
miri isolation configuration using two flags
Instead of using a single flag for both to disable isolation and to configure error behaviour, use a dedicated flag for each. For the former, continue using `-Zmiri-disable-isolation`. For the latter, replaced `-Zmiri-isolated-op` with `-Zmiri-isolation-error` flag to control the error behaviour of miri when op is run in isolation.
1 parent 2089976 commit f28165e

File tree

8 files changed

+82
-42
lines changed

8 files changed

+82
-42
lines changed

src/bin/miri.rs

+33-13
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ fn main() {
263263
let mut miri_config = miri::MiriConfig::default();
264264
let mut rustc_args = vec![];
265265
let mut after_dashdash = false;
266+
267+
// If user has explicitly enabled isolation
268+
let mut isolation_enabled: Option<bool> = None;
266269
for arg in env::args() {
267270
if rustc_args.is_empty() {
268271
// Very first arg: binary name.
@@ -291,8 +294,38 @@ fn main() {
291294
miri_config.check_abi = false;
292295
}
293296
"-Zmiri-disable-isolation" => {
297+
if let Some(true) = isolation_enabled {
298+
panic!(
299+
"-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error"
300+
);
301+
} else {
302+
isolation_enabled = Some(false);
303+
}
294304
miri_config.isolated_op = miri::IsolatedOp::Allow;
295305
}
306+
arg if arg.starts_with("-Zmiri-isolation-error=") => {
307+
if let Some(false) = isolation_enabled {
308+
panic!(
309+
"-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"
310+
);
311+
} else {
312+
isolation_enabled = Some(true);
313+
}
314+
315+
miri_config.isolated_op = match arg
316+
.strip_prefix("-Zmiri-isolation-error=")
317+
.unwrap()
318+
{
319+
"abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort),
320+
"ignore" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning),
321+
"warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning),
322+
"warn-nobacktrace" =>
323+
miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace),
324+
_ => panic!(
325+
"-Zmiri-isolation-error must be `abort`, `ignore`, `warn`, or `warn-nobacktrace`"
326+
),
327+
};
328+
}
296329
"-Zmiri-ignore-leaks" => {
297330
miri_config.ignore_leaks = true;
298331
}
@@ -385,19 +418,6 @@ fn main() {
385418
let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap();
386419
miri_config.measureme_out = Some(measureme_out.to_string());
387420
}
388-
arg if arg.starts_with("-Zmiri-isolated-op=") => {
389-
let action = match arg.strip_prefix("-Zmiri-isolated-op=").unwrap() {
390-
"hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning),
391-
"warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning),
392-
"warn-nobacktrace" =>
393-
miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace),
394-
"allow" => miri::IsolatedOp::Allow,
395-
_ => panic!(
396-
"-Zmiri-isolated-op must be `hide`, `warn`, `warn-nobacktrace`, or `allow`"
397-
),
398-
};
399-
miri_config.isolated_op = action;
400-
}
401421
_ => {
402422
// Forward to rustc.
403423
rustc_args.push(arg);

src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub fn report_error<'tcx, 'mir>(
8484
#[rustfmt::skip]
8585
let helps = match info {
8686
UnsupportedInIsolation(_) =>
87-
vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))],
87+
vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation; or pass `-Zmiri-isolation-error=warn to configure miri to warn about isolation and continue instead of aborting"))],
8888
ExperimentalUb { url, .. } =>
8989
vec![
9090
(None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),

src/eval.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,27 @@ pub enum AlignmentCheck {
2424

2525
#[derive(Copy, Clone, Debug, PartialEq)]
2626
pub enum RejectOpWith {
27-
/// Do not print warning about rejected isolated op
27+
/// Isolated op is rejected with an abort of the machine.
28+
Abort,
29+
30+
/// If not Abort, miri returns an error for an isolated op.
31+
/// Following options determine if user should be warned about such error.
32+
/// Do not print warning about rejected isolated op.
2833
NoWarning,
2934

30-
/// Print a warning about rejected isolated op, with backtrace
35+
/// Print a warning about rejected isolated op, with backtrace.
3136
Warning,
3237

33-
/// Print a warning about rejected isolated op, without backtrace
38+
/// Print a warning about rejected isolated op, without backtrace.
3439
WarningWithoutBacktrace,
3540
}
3641

3742
#[derive(Copy, Clone, Debug, PartialEq)]
3843
pub enum IsolatedOp {
39-
/// Reject op requiring communication with the host. Usually, miri
40-
/// returns an error code for such op, and prints a warning
41-
/// about it. Warning levels are controlled by `RejectOpWith` enum.
44+
/// Reject an op requiring communication with the host. By
45+
/// default, miri rejects the op with an abort. If not, it returns
46+
/// an error code, and prints a warning about it. Warning levels
47+
/// are controlled by `RejectOpWith` enum.
4248
Reject(RejectOpWith),
4349

4450
/// Execute op requiring communication with the host, i.e. disable isolation.
@@ -93,7 +99,7 @@ impl Default for MiriConfig {
9399
stacked_borrows: true,
94100
check_alignment: AlignmentCheck::Int,
95101
check_abi: true,
96-
isolated_op: IsolatedOp::Reject(RejectOpWith::WarningWithoutBacktrace),
102+
isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
97103
ignore_leaks: false,
98104
excluded_env_vars: vec![],
99105
args: vec![],

src/helpers.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -392,28 +392,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
392392
/// case.
393393
fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> {
394394
if !self.eval_context_ref().machine.communicate() {
395-
isolation_error(name)?;
395+
self.reject_in_isolation(name, RejectOpWith::Abort)?;
396396
}
397397
Ok(())
398398
}
399399

400400
/// Helper function used inside the shims of foreign functions which reject the op
401401
/// when isolation is enabled. It is used to print a warning/backtrace about the rejection.
402-
fn report_rejected_op(&self, op_name: &str, reject_with: RejectOpWith) {
402+
fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> InterpResult<'tcx> {
403403
let this = self.eval_context_ref();
404404
match reject_with {
405+
RejectOpWith::Abort => isolation_abort_error(op_name),
405406
RejectOpWith::WarningWithoutBacktrace => {
406407
let msg = format!("`{}` was made to return an error due to isolation", op_name);
407408
let mut warn = this.tcx.sess.struct_warn(&msg);
408-
warn.note("run with -Zmiri-isolated-op=warn to get warning with a backtrace");
409-
warn.note("run with -Zmiri-isolated-op=hide to hide warning");
410-
warn.note("run with -Zmiri-isolated-op=allow to disable isolation");
409+
warn.note("run with -Zmiri-isolation-error=warn to get warning with a backtrace");
410+
warn.note("run with -Zmiri-isolation-error=ignore to hide warning");
411+
warn.note("run with -Zmiri-disable-isolation to disable isolation");
411412
warn.emit();
413+
Ok(())
412414
}
413415
RejectOpWith::Warning => {
414416
register_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string()));
417+
Ok(())
415418
}
416-
RejectOpWith::NoWarning => {} // no warning
419+
RejectOpWith::NoWarning => Ok(()), // no warning
417420
}
418421
}
419422

@@ -663,10 +666,20 @@ where
663666
throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
664667
}
665668

666-
pub fn isolation_error(name: &str) -> InterpResult<'static> {
667-
// FIXME: This function has been deprecated. It's only used for
668-
// the ops which are not converted to return a proper error code
669-
// in isolation.
669+
/// Check that the ABI is what we expect.
670+
pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
671+
if abi == exp_abi {
672+
Ok(())
673+
} else {
674+
throw_ub_format!(
675+
"calling a function with ABI {} using caller ABI {}",
676+
exp_abi.name(),
677+
abi.name()
678+
)
679+
}
680+
}
681+
682+
pub fn isolation_abort_error(name: &str) -> InterpResult<'static> {
670683
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
671684
"{} not available when isolation is enabled",
672685
name,

src/shims/env.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
323323
);
324324

325325
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
326+
this.reject_in_isolation("getcwd", reject_with)?;
326327
let err = Error::new(ErrorKind::NotFound, "rejected due to isolation");
327328
this.set_last_error_from_io_error(err)?;
328-
this.report_rejected_op("getcwd", reject_with);
329329
} else {
330330
let buf = this.read_scalar(&buf_op)?.check_init()?;
331331
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
@@ -355,9 +355,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
355355
this.assert_target_os("windows", "GetCurrentDirectoryW");
356356

357357
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
358+
this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?;
358359
let err = Error::new(ErrorKind::NotFound, "rejected due to isolation");
359360
this.set_last_error_from_io_error(err)?;
360-
this.report_rejected_op("GetCurrentDirectoryW", reject_with);
361361
} else {
362362
let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
363363
let buf = this.read_scalar(buf_op)?.check_init()?;
@@ -383,9 +383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
383383
);
384384

385385
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
386+
this.reject_in_isolation("chdir", reject_with)?;
386387
let err = Error::new(ErrorKind::NotFound, "rejected due to isolation");
387388
this.set_last_error_from_io_error(err)?;
388-
this.report_rejected_op("chdir", reject_with);
389389

390390
Ok(-1)
391391
} else {
@@ -412,9 +412,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
412412
this.assert_target_os("windows", "SetCurrentDirectoryW");
413413

414414
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
415+
this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?;
415416
let err = Error::new(ErrorKind::NotFound, "rejected due to isolation");
416417
this.set_last_error_from_io_error(err)?;
417-
this.report_rejected_op("SetCurrentDirectoryW", reject_with);
418418

419419
Ok(0)
420420
} else {

src/shims/posix/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ impl FileDescriptor for io::Stdin {
127127
) -> InterpResult<'tcx, io::Result<usize>> {
128128
if !communicate_allowed {
129129
// We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
130-
helpers::isolation_error("`read` from stdin")?;
130+
helpers::isolation_abort_error("`read` from stdin")?;
131131
}
132132
Ok(Read::read(self, bytes))
133133
}

tests/run-pass/current_dir_with_isolation.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// compile-flags: -Zmiri-isolation-error=warn-nobacktrace
12
use std::env;
23
use std::io::ErrorKind;
34

Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
warning: `getcwd` was made to return an error due to isolation
22
|
3-
= note: run with -Zmiri-isolated-op=warn to get warning with a backtrace
4-
= note: run with -Zmiri-isolated-op=hide to hide warning
5-
= note: run with -Zmiri-isolated-op=allow to disable isolation
3+
= note: run with -Zmiri-isolation-error=warn to get warning with a backtrace
4+
= note: run with -Zmiri-isolation-error=ignore to hide warning
5+
= note: run with -Zmiri-disable-isolation to disable isolation
66

77
warning: `chdir` was made to return an error due to isolation
88
|
9-
= note: run with -Zmiri-isolated-op=warn to get warning with a backtrace
10-
= note: run with -Zmiri-isolated-op=hide to hide warning
11-
= note: run with -Zmiri-isolated-op=allow to disable isolation
9+
= note: run with -Zmiri-isolation-error=warn to get warning with a backtrace
10+
= note: run with -Zmiri-isolation-error=ignore to hide warning
11+
= note: run with -Zmiri-disable-isolation to disable isolation
1212

0 commit comments

Comments
 (0)