Skip to content

Commit d940d0b

Browse files
Patrick-6RalfJung
andcommitted
Implement skeleton code for adding GenMC support to Miri (not yet functional).
- Add a cargo feature to enable GenMC support (off by default) - Add support for GenMC datastructures to MiriMachine - Adjust several functions where GenMC needs to be informed about relevant events (e.g., atomic accesses) - Add skeleton code for parsing GenMC command line arguments - Some cleanup - Finish sentences with a `.` - Fix some spelling errors/typos Co-authored-by: Ralf Jung <[email protected]>
1 parent a8da0fd commit d940d0b

File tree

22 files changed

+1254
-307
lines changed

22 files changed

+1254
-307
lines changed

src/tools/miri/.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ tex/*/out
99
*.mm_profdata
1010
perf.data
1111
perf.data.old
12-
flamegraph.svg
12+
flamegraph*.svg
13+
rustc-ice*.txt
1314
tests/native-lib/libtestlib.so
1415
.auto-*
16+
17+
/genmc/

src/tools/miri/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ harness = false
6565

6666
[features]
6767
default = ["stack-cache"]
68+
genmc = []
6869
stack-cache = []
6970
stack-cache-consistency-check = ["stack-cache"]
7071

src/tools/miri/src/alloc_addresses/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
114114
memory_kind: MemoryKind,
115115
) -> InterpResult<'tcx, u64> {
116116
let this = self.eval_context_ref();
117-
let mut rng = this.machine.rng.borrow_mut();
118117
let info = this.get_alloc_info(alloc_id);
118+
119+
// Miri's address assignment leaks state across thread boundaries, which is incompatible
120+
// with GenMC execution. So we instead let GenMC assign addresses to allocations.
121+
if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
122+
let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?;
123+
return interp_ok(addr);
124+
}
125+
126+
let mut rng = this.machine.rng.borrow_mut();
119127
// This is either called immediately after allocation (and then cached), or when
120128
// adjusting `tcx` pointers (which never get freed). So assert that we are looking
121129
// at a live allocation. This also ensures that we never re-assign an address to an
@@ -490,7 +498,7 @@ impl<'tcx> MiriMachine<'tcx> {
490498
// Also remember this address for future reuse.
491499
let thread = self.threads.active_thread();
492500
global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || {
493-
if let Some(data_race) = &self.data_race {
501+
if let Some(data_race) = self.data_race.as_vclocks_ref() {
494502
data_race.release_clock(&self.threads, |clock| clock.clone())
495503
} else {
496504
VClock::default()

src/tools/miri/src/bin/miri.rs

+51-9
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ use std::env::{self, VarError};
2828
use std::num::NonZero;
2929
use std::ops::Range;
3030
use std::path::PathBuf;
31+
use std::rc::Rc;
3132
use std::str::FromStr;
3233
use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
3334
use std::sync::{Arc, Once};
3435

3536
use miri::{
36-
BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType, ProvenanceMode, RetagFields,
37-
ValidationMode,
37+
BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType,
38+
ProvenanceMode, RetagFields, ValidationMode,
3839
};
3940
use rustc_abi::ExternAbi;
4041
use rustc_data_structures::sync;
@@ -60,6 +61,8 @@ use tracing::debug;
6061
struct MiriCompilerCalls {
6162
miri_config: Option<MiriConfig>,
6263
many_seeds: Option<ManySeedsConfig>,
64+
/// Settings for using GenMC with Miri.
65+
genmc_config: Option<GenmcConfig>,
6366
}
6467

6568
struct ManySeedsConfig {
@@ -68,8 +71,12 @@ struct ManySeedsConfig {
6871
}
6972

7073
impl MiriCompilerCalls {
71-
fn new(miri_config: MiriConfig, many_seeds: Option<ManySeedsConfig>) -> Self {
72-
Self { miri_config: Some(miri_config), many_seeds }
74+
fn new(
75+
miri_config: MiriConfig,
76+
many_seeds: Option<ManySeedsConfig>,
77+
genmc_config: Option<GenmcConfig>,
78+
) -> Self {
79+
Self { miri_config: Some(miri_config), many_seeds, genmc_config }
7380
}
7481
}
7582

@@ -179,6 +186,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
179186
optimizations is usually marginal at best.");
180187
}
181188

189+
if let Some(genmc_config) = &self.genmc_config {
190+
let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config));
191+
192+
todo!("GenMC mode not yet implemented");
193+
};
194+
182195
if let Some(many_seeds) = self.many_seeds.take() {
183196
assert!(config.seed.is_none());
184197
let exit_code = sync::IntoDynSyncSend(AtomicI32::new(rustc_driver::EXIT_SUCCESS));
@@ -187,8 +200,14 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
187200
let mut config = config.clone();
188201
config.seed = Some((*seed).into());
189202
eprintln!("Trying seed: {seed}");
190-
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
191-
.unwrap_or(rustc_driver::EXIT_FAILURE);
203+
let return_code = miri::eval_entry(
204+
tcx,
205+
entry_def_id,
206+
entry_type,
207+
&config,
208+
/* genmc_ctx */ None,
209+
)
210+
.unwrap_or(rustc_driver::EXIT_FAILURE);
192211
if return_code != rustc_driver::EXIT_SUCCESS {
193212
eprintln!("FAILING SEED: {seed}");
194213
if !many_seeds.keep_going {
@@ -206,11 +225,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
206225
}
207226
std::process::exit(exit_code.0.into_inner());
208227
} else {
209-
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
228+
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
210229
.unwrap_or_else(|| {
211230
tcx.dcx().abort_if_errors();
212231
rustc_driver::EXIT_FAILURE
213232
});
233+
214234
std::process::exit(return_code);
215235
}
216236

@@ -506,6 +526,7 @@ fn main() {
506526
let mut many_seeds_keep_going = false;
507527
let mut miri_config = MiriConfig::default();
508528
miri_config.env = env_snapshot;
529+
let mut genmc_config = None;
509530

510531
let mut rustc_args = vec![];
511532
let mut after_dashdash = false;
@@ -603,6 +624,10 @@ fn main() {
603624
many_seeds = Some(0..64);
604625
} else if arg == "-Zmiri-many-seeds-keep-going" {
605626
many_seeds_keep_going = true;
627+
} else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") {
628+
// FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking.
629+
miri_config.borrow_tracker = None;
630+
GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg);
606631
} else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") {
607632
miri_config.forwarded_env_vars.push(param.to_owned());
608633
} else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") {
@@ -697,7 +722,7 @@ fn main() {
697722
rustc_args.push(arg);
698723
}
699724
}
700-
// `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows`
725+
// `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows`.
701726
if miri_config.unique_is_unique
702727
&& !matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows))
703728
{
@@ -734,7 +759,24 @@ fn main() {
734759
let many_seeds =
735760
many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going });
736761

762+
// Validate settings for data race detection and GenMC mode.
763+
assert_eq!(genmc_config.is_some(), miri_config.genmc_mode);
764+
if genmc_config.is_some() {
765+
if !miri_config.data_race_detector {
766+
show_error!("Cannot disable data race detection in GenMC mode (currently)");
767+
} else if !miri_config.weak_memory_emulation {
768+
show_error!("Cannot disable weak memory emulation in GenMC mode");
769+
}
770+
} else if miri_config.weak_memory_emulation && !miri_config.data_race_detector {
771+
show_error!(
772+
"Weak memory emulation cannot be enabled when the data race detector is disabled"
773+
);
774+
};
775+
737776
debug!("rustc arguments: {:?}", rustc_args);
738777
debug!("crate arguments: {:?}", miri_config.args);
739-
run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
778+
run_compiler_and_exit(
779+
&rustc_args,
780+
&mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config),
781+
)
740782
}

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
740740
if let Some(access) = access {
741741
assert_eq!(access, AccessKind::Write);
742742
// Make sure the data race model also knows about this.
743-
if let Some(data_race) = alloc_extra.data_race.as_mut() {
743+
if let Some(data_race) = alloc_extra.data_race.as_vclocks_mut() {
744744
data_race.write(
745745
alloc_id,
746746
range,
@@ -789,7 +789,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
789789
if let Some(access) = access {
790790
assert_eq!(access, AccessKind::Read);
791791
// Make sure the data race model also knows about this.
792-
if let Some(data_race) = alloc_extra.data_race.as_ref() {
792+
if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() {
793793
data_race.read(
794794
alloc_id,
795795
range,

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
317317

318318
// Also inform the data race model (but only if any bytes are actually affected).
319319
if range.size.bytes() > 0 && new_perm.initial_read {
320-
if let Some(data_race) = alloc_extra.data_race.as_ref() {
320+
if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() {
321321
data_race.read(
322322
alloc_id,
323323
range,

0 commit comments

Comments
 (0)