Skip to content

Commit ce3f903

Browse files
authored
Rollup merge of #148991 - RalfJung:genmc-exit, r=oli-obk
miri genmc: fix exit() handling In genmc mode, Miri does not want to stop execution when `exit` is called. Instead we want to continue running other threads to ensure we covered all possible concurrent behaviors (including the ones where the exiting thread was delayed so the other threads took their turns first). However, the core interpreter has a sanity check that prevents us from just doing nothing in `exit`. This leaves us in a pickle: there's nowhere we can jump to (exit has return type `!` so there's no next block), but if we don't jump anywhere we ICE. The first commit fixes that by disabling the sanity check when there is no block to jump to. That still catches the mistake of forgetting to jump for the vast majority of shims. We currently don't build Miri's genmc integration in rustc CI so I had to hack the feature into the bootstrap miri integration. That turned out to use the wrong Miri binary, which is fixed by the second commit: we can just rely on CARGO_BIN_EXE_miri, there's no need for a MIRI environment variable. r? ``@oli-obk``
2 parents 5a875b8 + 783780c commit ce3f903

File tree

6 files changed

+142
-5
lines changed

6 files changed

+142
-5
lines changed

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
561561
if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
562562
)?;
563563
// Sanity-check that `eval_fn_call` either pushed a new frame or
564-
// did a jump to another block.
565-
if self.frame_idx() == old_stack && self.frame().loc == old_loc {
564+
// did a jump to another block. We disable the sanity check for functions that
565+
// can't return, since Miri sometimes does have to keep the location the same
566+
// for those (which is fine since execution will continue on a different thread).
567+
if target.is_some() && self.frame_idx() == old_stack && self.frame().loc == old_loc
568+
{
566569
span_bug!(terminator.source_info.span, "evaluating this call made no progress");
567570
}
568571
}

src/bootstrap/src/core/build_steps/test.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,6 @@ impl Step for Miri {
722722
// miri tests need to know about the stage sysroot
723723
cargo.env("MIRI_SYSROOT", &miri_sysroot);
724724
cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
725-
cargo.env("MIRI", &miri.tool_path);
726725

727726
// Set the target.
728727
cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());

src/tools/miri/src/shims/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
538538
code,
539539
crate::concurrency::ExitType::ExitCalled,
540540
)?;
541-
todo!(); // FIXME(genmc): Add a way to return here that is allowed to not do progress (can't use existing EmulateItemResult variants).
541+
return interp_ok(EmulateItemResult::AlreadyJumped);
542542
}
543543
throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
544544
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows
2+
3+
fn main() {
4+
std::thread::spawn(|| {
5+
unsafe { std::hint::unreachable_unchecked() }; //~ERROR: entering unreachable code
6+
});
7+
// If we exit immediately, we might entirely miss the UB in the other thread.
8+
std::process::exit(0);
9+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
Running GenMC Verification...
2+
warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures.
3+
--> RUSTLIB/std/src/thread/mod.rs:LL:CC
4+
|
5+
LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) {
6+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code
7+
|
8+
= note: BACKTRACE:
9+
= note: inside `std::thread::ThreadId::new` at RUSTLIB/std/src/thread/mod.rs:LL:CC
10+
= note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC
11+
= note: inside `std::thread::current::id::get_or_init` at RUSTLIB/std/src/thread/current.rs:LL:CC
12+
= note: inside `std::thread::current_id` at RUSTLIB/std/src/thread/current.rs:LL:CC
13+
= note: inside `std::rt::init` at RUSTLIB/std/src/rt.rs:LL:CC
14+
= note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
15+
= note: inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
16+
= note: inside `std::panicking::catch_unwind::<isize, {closure@std::rt::lang_start_internal::{closure#0}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
17+
= note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
18+
= note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC
19+
= note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC
20+
21+
warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access.
22+
--> RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
23+
|
24+
LL | || self
25+
| ________________^
26+
LL | | .state
27+
LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
28+
| |____________________________________________________________________________________^ GenMC might miss possible behaviors of this code
29+
|
30+
= note: BACKTRACE:
31+
= note: inside `std::sys::sync::PLATFORM::futex::RwLock::read` at RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
32+
= note: inside `std::sync::RwLock::<()>::read` at RUSTLIB/std/src/sync/poison/rwlock.rs:LL:CC
33+
= note: inside `std::sys::env::PLATFORM::env_read_lock` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
34+
= note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
35+
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
36+
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
37+
= note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
38+
= note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC
39+
= note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC
40+
= note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC
41+
note: inside `main`
42+
--> tests/genmc/fail/shims/exit.rs:LL:CC
43+
|
44+
LL | / std::thread::spawn(|| {
45+
LL | | unsafe { std::hint::unreachable_unchecked() };
46+
LL | | });
47+
| |______^
48+
49+
warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures.
50+
--> RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
51+
|
52+
LL | || self
53+
| ________________^
54+
LL | | .state
55+
LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
56+
| |____________________________________________________________________________________^ GenMC might miss possible behaviors of this code
57+
|
58+
= note: BACKTRACE:
59+
= note: inside `std::sys::sync::PLATFORM::futex::RwLock::read` at RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
60+
= note: inside `std::sync::RwLock::<()>::read` at RUSTLIB/std/src/sync/poison/rwlock.rs:LL:CC
61+
= note: inside `std::sys::env::PLATFORM::env_read_lock` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
62+
= note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
63+
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
64+
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
65+
= note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
66+
= note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC
67+
= note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC
68+
= note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC
69+
note: inside `main`
70+
--> tests/genmc/fail/shims/exit.rs:LL:CC
71+
|
72+
LL | / std::thread::spawn(|| {
73+
LL | | unsafe { std::hint::unreachable_unchecked() };
74+
LL | | });
75+
| |______^
76+
77+
warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures.
78+
--> RUSTLIB/std/src/rt.rs:LL:CC
79+
|
80+
LL | / CLEANUP.call_once(|| unsafe {
81+
LL | | // Flush stdout and disable buffering.
82+
LL | | crate::io::cleanup();
83+
... |
84+
LL | | });
85+
| |______^ GenMC might miss possible behaviors of this code
86+
|
87+
= note: BACKTRACE:
88+
= note: inside `std::rt::cleanup` at RUSTLIB/std/src/rt.rs:LL:CC
89+
= note: inside `std::process::exit` at RUSTLIB/std/src/process.rs:LL:CC
90+
note: inside `main`
91+
--> tests/genmc/fail/shims/exit.rs:LL:CC
92+
|
93+
LL | std::process::exit(0);
94+
| ^^^^^^^^^^^^^^^^^^^^^
95+
96+
warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access.
97+
--> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC
98+
|
99+
LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) {
100+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code
101+
|
102+
= note: BACKTRACE:
103+
= note: inside `std::sys::exit_guard::unique_thread_exit` at RUSTLIB/std/src/sys/exit_guard.rs:LL:CC
104+
= note: inside `std::sys::pal::PLATFORM::os::exit` at RUSTLIB/std/src/sys/pal/PLATFORM/os.rs:LL:CC
105+
= note: inside `std::process::exit` at RUSTLIB/std/src/process.rs:LL:CC
106+
note: inside `main`
107+
--> tests/genmc/fail/shims/exit.rs:LL:CC
108+
|
109+
LL | std::process::exit(0);
110+
| ^^^^^^^^^^^^^^^^^^^^^
111+
112+
error: Undefined Behavior: entering unreachable code
113+
--> tests/genmc/fail/shims/exit.rs:LL:CC
114+
|
115+
LL | unsafe { std::hint::unreachable_unchecked() };
116+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
117+
|
118+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
119+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
120+
121+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
122+
123+
note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report
124+
125+
error: aborting due to 1 previous error; 5 warnings emitted
126+

src/tools/miri/tests/ui.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ enum Mode {
2727
}
2828

2929
fn miri_path() -> PathBuf {
30-
PathBuf::from(env::var("MIRI").unwrap_or_else(|_| env!("CARGO_BIN_EXE_miri").into()))
30+
env!("CARGO_BIN_EXE_miri").into()
3131
}
3232

3333
// Build the shared object file for testing native function calls.

0 commit comments

Comments
 (0)