Closed
Description
In the project I'm working on we have many tests that we'd potentially like to run with Miri in our CI/CD. These tests may invoke syscalls or other unsupported FFI operations that we would like to suppress and treat as successful tests for a few reasons:
- Reduce the developer burden of applying
cfg(miri)
to ignore specific tests. - Tests invoking unsupported foreign functions will still be emulated up until they perform the foreign function call. Testing to this point may still yield valuable results.
- Opting out of specific tests requires conscious thought of whether a test should be re-enabled after a refactoring to remove a foreign function call that would otherwise raise an error.
I believe this could be handled with the introduction of a new -Z
variable, -Zmiri-ignore-ffi-failure
, that would simply treat these failures as an early exit with status code 0. Here's the proposed change to Miri:
Click to view diff
diff --git a/src/bin/miri.rs b/src/bin/miri.rs
index 4a1ea3a5..78f9b196 100644
--- a/src/bin/miri.rs
+++ b/src/bin/miri.rs
@@ -230,6 +230,9 @@ fn main() {
"-Zmiri-disable-isolation" => {
miri_config.communicate = true;
}
+ "-Zmiri-ignore-ffi-failures" => {
+ miri_config.ignore_unsupported_ffi_failures = true;
+ }
"-Zmiri-ignore-leaks" => {
miri_config.ignore_leaks = true;
}
diff --git a/src/eval.rs b/src/eval.rs
index 1e46015f..8acc3020 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -35,6 +35,8 @@ pub struct MiriConfig {
pub communicate: bool,
/// Determines if memory leaks should be ignored.
pub ignore_leaks: bool,
+ /// Determines if failures caused by unsupported FFI failures should be ignored.
+ pub ignore_unsupported_ffi_failures: bool,
/// Environment variables that should always be isolated from the host.
pub excluded_env_vars: Vec<String>,
/// Command-line arguments passed to the interpreted program.
@@ -206,6 +208,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
// Copy setting before we move `config`.
let ignore_leaks = config.ignore_leaks;
+ let ignore_unsupported_ffi_failures= config.ignore_unsupported_ffi_failures;
let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
Ok(v) => v,
@@ -267,6 +270,14 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
}
Some(return_code)
}
- Err(e) => report_error(&ecx, e),
+ Err(e) => {
+ if let InterpError::Unsupported(UnsupportedOpInfo::UnsupportedForeignFunction(_name)) = e.kind() {
+ if ignore_unsupported_ffi_failures {
+ // clean exit
+ return Some(0);
+ }
+ }
+ report_error(&ecx, e)
+ }
}
}
diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs
index f7d7706e..d78e6da3 100644
--- a/src/shims/posix/linux/foreign_items.rs
+++ b/src/shims/posix/linux/foreign_items.rs
@@ -214,7 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_null(dest)?;
}
- _ => throw_unsup_format!("can't call foreign function: {}", link_name),
+ _ => throw_unsup_foreign_function(link_name),
};
Ok(true)
diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs
index 9a7d3be1..03656395 100644
--- a/src/shims/posix/macos/foreign_items.rs
+++ b/src/shims/posix/macos/foreign_items.rs
@@ -156,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(addr, dest)?;
}
- _ => throw_unsup_format!("can't call foreign function: {}", link_name),
+ _ => throw_unsup_foreign_function(link_name),
};
Ok(true)
diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs
index b246ccc3..e4211669 100644
--- a/src/shims/windows/foreign_items.rs
+++ b/src/shims/windows/foreign_items.rs
@@ -415,7 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(Scalar::from_i32(1), dest)?;
}
- _ => throw_unsup_format!("can't call foreign function: {}", link_name),
+ _ => throw_unsup_foreign_function(link_name),
}
Ok(true)
This would require changes to rustc_middle
as well for a new macro, throw_unsup_foreign_function
, and a new UnsupportedOpInfo variant, UnsupportedOpInfo::UnsupportedForeignFunction(String)
.
Metadata
Metadata
Assignees
Labels
No labels