Add support for panicking in the emulated application when unsupported syscalls are encountered

This commit is contained in:
Lander Brandt 2021-05-26 16:29:01 -07:00
parent 81ee877f71
commit ae237098f8
12 changed files with 64 additions and 6 deletions

View File

@ -228,6 +228,11 @@ 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-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
execution). Note that code might not expect these operations to ever panic, so
this flag can lead to strange (mis)behavior.
* `-Zmiri-seed=<hex>` configures the seed of the RNG that Miri uses to resolve
non-determinism. This RNG is used to pick base addresses for allocations.
When isolation is enabled (the default), this is also used to emulate system

View File

@ -296,6 +296,9 @@ fn main() {
"-Zmiri-ignore-leaks" => {
miri_config.ignore_leaks = true;
}
"-Zmiri-panic-on-unsupported" => {
miri_config.panic_on_unsupported = true;
}
"-Zmiri-track-raw-pointers" => {
miri_config.track_raw = true;
}

View File

@ -59,6 +59,8 @@ pub struct MiriConfig {
/// If `Some`, enable the `measureme` profiler, writing results to a file
/// with the specified prefix.
pub measureme_out: Option<String>,
/// Panic when unsupported functionality is encountered
pub panic_on_unsupported: bool,
}
impl Default for MiriConfig {
@ -80,6 +82,7 @@ impl Default for MiriConfig {
data_race_detector: true,
cmpxchg_weak_failure_rate: 0.8,
measureme_out: None,
panic_on_unsupported: false,
}
}
}

View File

@ -636,6 +636,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
== this.tcx.def_path(start_fn).krate
})
}
/// Handler that should be called when unsupported functionality is encountered.
/// This function will either panic within the context of the emulated application
/// or return an error in the Miri process context
///
/// Return value of `Ok(bool)` indicates whether execution should continue.
fn handle_unsupported<S: AsRef<str>>(&mut self, error_msg: S) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
if this.machine.panic_on_unsupported {
// message is slightly different here to make automated analysis easier
let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref());
this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?;
return Ok(());
} else {
throw_unsup_format!("{}", error_msg.as_ref());
}
}
}
/// Check that the number of args is what we expect.

View File

@ -297,6 +297,11 @@ pub struct Evaluator<'mir, 'tcx> {
/// Cache of `Instance` exported under the given `Symbol` name.
pub(crate) exported_symbols_cache: FxHashMap<Symbol, Instance<'tcx>>,
/// Whether to raise a panic in the context of the evaluated process when unsupported
/// functionality is encountered. If `false`, an error is propagated in the Miri application context
/// instead (default behavior)
pub(crate) panic_on_unsupported: bool,
}
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
@ -326,6 +331,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
profiler,
string_cache: Default::default(),
exported_symbols_cache: FxHashMap::default(),
panic_on_unsupported: config.panic_on_unsupported,
}
}
}

View File

@ -259,7 +259,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
if let Some(body) = this.lookup_exported_symbol(link_name_sym)? {
return Ok(Some(body));
}
throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
this.handle_unsupported(format!(
"can't call (diverging) foreign function: {}",
link_name
))?;
return Ok(None);
}
},
Some(p) => p,
@ -276,7 +280,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
if let Some(body) = this.lookup_exported_symbol(link_name_sym)? {
return Ok(Some(body));
}
throw_unsup_format!("can't call foreign function: {}", link_name);
this.handle_unsupported(format!("can't call foreign function: {}", link_name))?;
return Ok(None);
}
}

View File

@ -161,7 +161,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
}
/// Starta a panic in the interpreter with the given message as payload.
/// Start a panic in the interpreter with the given message as payload.
fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> {
let this = self.eval_context_mut();

View File

@ -183,7 +183,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
id if id == sys_futex => {
futex(this, args, dest)?;
}
id => throw_unsup_format!("Miri does not support syscall ID {}", id),
id => {
this.handle_unsupported(format!("can't execute syscall with ID {}", id))?;
return Ok(EmulateByNameResult::NotSupported);
}
}
}

View File

@ -343,7 +343,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Better error for attempts to create a thread
"CreateThread" => {
this.check_abi(abi, Abi::System { unwind: false })?;
throw_unsup_format!("Miri does not support concurrency on Windows");
this.handle_unsupported("can't create threads on Windows")?;
return Ok(EmulateByNameResult::AlreadyJumped);
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.

View File

@ -3,7 +3,7 @@
use std::thread;
// error-pattern: Miri does not support concurrency on Windows
// error-pattern: can't create threads on Windows
fn main() {
thread::spawn(|| {});

View File

@ -0,0 +1,11 @@
// compile-flags: -Zmiri-panic-on-unsupported
fn main() {
extern "Rust" {
fn foo();
}
unsafe {
foo();
}
}

View File

@ -0,0 +1,2 @@
thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:9:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace