Skip to content

Commit e5c3af6

Browse files
committed
Auto merge of #1818 - landaire:feature/panic-on-unsupported-syscalls, r=RalfJung
Add support for panicking in the emulated application when unsupported functionality is encountered This PR fixes #1807 and allows an optional flag to be specified to panic when an unsupported syscall is encountered. In essence, instead of bubbling up an error in the context of the Miri application Miri will panic within the context of the *emulated* application. This feature is desired to allow CI pipelines to determine if a Miri failure is unsupported functionality or actual UB. Please read [this comment](#1807 (comment)) for the rationale behind this change. Note: this change does not cover all cases where unsupported functionality errors may be raised. If you search the repo for `throw_unsup_format!` there are many cases that I think are less likely to occur and may still be problematic for some folks. TODO: - [x] README documentation on this new flag - [x] Add tests
2 parents 6c63506 + ae23709 commit e5c3af6

File tree

12 files changed

+64
-6
lines changed

12 files changed

+64
-6
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ environment variable:
235235
This can be used to find which parts of your program are executing slowly under Miri.
236236
The profile is written out to a file with the prefix `<name>`, and can be processed
237237
using the tools in the repository https://github.com/rust-lang/measureme.
238+
* `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality,
239+
such as FFI and unsupported syscalls, panic within the context of the emulated
240+
application instead of raising an error within the context of Miri (and halting
241+
execution). Note that code might not expect these operations to ever panic, so
242+
this flag can lead to strange (mis)behavior.
238243
* `-Zmiri-seed=<hex>` configures the seed of the RNG that Miri uses to resolve
239244
non-determinism. This RNG is used to pick base addresses for allocations.
240245
When isolation is enabled (the default), this is also used to emulate system

src/bin/miri.rs

+3
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@ fn main() {
329329
"-Zmiri-ignore-leaks" => {
330330
miri_config.ignore_leaks = true;
331331
}
332+
"-Zmiri-panic-on-unsupported" => {
333+
miri_config.panic_on_unsupported = true;
334+
}
332335
"-Zmiri-track-raw-pointers" => {
333336
miri_config.track_raw = true;
334337
}

src/eval.rs

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ pub struct MiriConfig {
8888
/// If `Some`, enable the `measureme` profiler, writing results to a file
8989
/// with the specified prefix.
9090
pub measureme_out: Option<String>,
91+
/// Panic when unsupported functionality is encountered
92+
pub panic_on_unsupported: bool,
9193
}
9294

9395
impl Default for MiriConfig {
@@ -109,6 +111,7 @@ impl Default for MiriConfig {
109111
data_race_detector: true,
110112
cmpxchg_weak_failure_rate: 0.8,
111113
measureme_out: None,
114+
panic_on_unsupported: false,
112115
}
113116
}
114117
}

src/helpers.rs

+17
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
660660
== this.tcx.def_path(start_fn).krate
661661
})
662662
}
663+
664+
/// Handler that should be called when unsupported functionality is encountered.
665+
/// This function will either panic within the context of the emulated application
666+
/// or return an error in the Miri process context
667+
///
668+
/// Return value of `Ok(bool)` indicates whether execution should continue.
669+
fn handle_unsupported<S: AsRef<str>>(&mut self, error_msg: S) -> InterpResult<'tcx, ()> {
670+
let this = self.eval_context_mut();
671+
if this.machine.panic_on_unsupported {
672+
// message is slightly different here to make automated analysis easier
673+
let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref());
674+
this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?;
675+
return Ok(());
676+
} else {
677+
throw_unsup_format!("{}", error_msg.as_ref());
678+
}
679+
}
663680
}
664681

665682
/// Check that the number of args is what we expect.

src/machine.rs

+6
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ pub struct Evaluator<'mir, 'tcx> {
298298

299299
/// Cache of `Instance` exported under the given `Symbol` name.
300300
pub(crate) exported_symbols_cache: FxHashMap<Symbol, Instance<'tcx>>,
301+
302+
/// Whether to raise a panic in the context of the evaluated process when unsupported
303+
/// functionality is encountered. If `false`, an error is propagated in the Miri application context
304+
/// instead (default behavior)
305+
pub(crate) panic_on_unsupported: bool,
301306
}
302307

303308
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
@@ -327,6 +332,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
327332
profiler,
328333
string_cache: Default::default(),
329334
exported_symbols_cache: FxHashMap::default(),
335+
panic_on_unsupported: config.panic_on_unsupported,
330336
}
331337
}
332338

src/shims/foreign_items.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
259259
if let Some(body) = this.lookup_exported_symbol(link_name_sym)? {
260260
return Ok(Some(body));
261261
}
262-
throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
262+
this.handle_unsupported(format!(
263+
"can't call (diverging) foreign function: {}",
264+
link_name
265+
))?;
266+
return Ok(None);
263267
}
264268
},
265269
Some(p) => p,
@@ -276,7 +280,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
276280
if let Some(body) = this.lookup_exported_symbol(link_name_sym)? {
277281
return Ok(Some(body));
278282
}
279-
throw_unsup_format!("can't call foreign function: {}", link_name);
283+
284+
this.handle_unsupported(format!("can't call foreign function: {}", link_name))?;
285+
return Ok(None);
280286
}
281287
}
282288

src/shims/panic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
161161
}
162162
}
163163

164-
/// Starta a panic in the interpreter with the given message as payload.
164+
/// Start a panic in the interpreter with the given message as payload.
165165
fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> {
166166
let this = self.eval_context_mut();
167167

src/shims/posix/linux/foreign_items.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
183183
id if id == sys_futex => {
184184
futex(this, args, dest)?;
185185
}
186-
id => throw_unsup_format!("Miri does not support syscall ID {}", id),
186+
id => {
187+
this.handle_unsupported(format!("can't execute syscall with ID {}", id))?;
188+
return Ok(EmulateByNameResult::NotSupported);
189+
}
187190
}
188191
}
189192

src/shims/windows/foreign_items.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
343343
// Better error for attempts to create a thread
344344
"CreateThread" => {
345345
this.check_abi(abi, Abi::System { unwind: false })?;
346-
throw_unsup_format!("Miri does not support concurrency on Windows");
346+
347+
this.handle_unsupported("can't create threads on Windows")?;
348+
return Ok(EmulateByNameResult::AlreadyJumped);
347349
}
348350

349351
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.

tests/compile-fail/concurrency/thread-spawn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use std::thread;
55

6-
// error-pattern: Miri does not support concurrency on Windows
6+
// error-pattern: can't create threads on Windows
77

88
fn main() {
99
thread::spawn(|| {});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// compile-flags: -Zmiri-panic-on-unsupported
2+
3+
fn main() {
4+
extern "Rust" {
5+
fn foo();
6+
}
7+
8+
unsafe {
9+
foo();
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:9:9
2+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

0 commit comments

Comments
 (0)