diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index d47967c0a4d3..878319415808 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -373,6 +373,12 @@ environment variable. We first document the most relevant and most commonly used ensure alignment. (The standard library `align_to` method works fine in both modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.) +* `-Zmiri-user-relevant-crates=,,...` extends the list of crates that Miri considers + "user-relevant". This affects the rendering of backtraces (for user-relevant crates, Miri shows + not just the function name but the actual code) and it affects the spans collected for data races + and aliasing violations (where Miri will show the span of the topmost non-`#[track_caller]` frame + in a user-relevant crate). When using `cargo miri`, the crates in the local workspace are always + considered user-relevant. The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 40ad571fe1ab..6ef6e340b3d9 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -710,6 +710,8 @@ fn main() { fatal_error!("-Zmiri-force-page-size requires a power of 2: {page_size}"); }; miri_config.page_size = Some(page_size); + } else if let Some(param) = arg.strip_prefix("-Zmiri-user-relevant-crates=") { + miri_config.user_relevant_crates.extend(param.split(',').map(|s| s.to_owned())); } else { // Forward to rustc. rustc_args.push(arg); diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 82ca38c3752b..20b506bad91e 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -115,6 +115,8 @@ pub struct MiriConfig { pub float_rounding_error: FloatRoundingErrorMode, /// Whether Miri artifically introduces short reads/writes on file descriptors. pub short_fd_operations: bool, + /// A list of crates that are considered user-relevant. + pub user_relevant_crates: Vec, } impl Default for MiriConfig { @@ -158,6 +160,7 @@ impl Default for MiriConfig { float_nondet: true, float_rounding_error: FloatRoundingErrorMode::Random, short_fd_operations: true, + user_relevant_crates: vec![], } } } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ab2804fae0d7..769e501c4533 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1091,7 +1091,7 @@ impl<'tcx> MiriMachine<'tcx> { /// This is the source of truth for the `is_user_relevant` flag in our `FrameExtra`. pub fn is_user_relevant(&self, frame: &Frame<'tcx, Provenance>) -> bool { let def_id = frame.instance().def_id(); - (def_id.is_local() || self.local_crates.contains(&def_id.krate)) + (def_id.is_local() || self.user_relevant_crates.contains(&def_id.krate)) && !frame.instance().def.requires_caller_location(self.tcx) } } @@ -1102,25 +1102,6 @@ pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> { ))) } -/// Retrieve the list of local crates that should have been passed by cargo-miri in -/// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { - // Convert the local crate names from the passed-in config into CrateNums so that they can - // be looked up quickly during execution - let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") - .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::>()) - .unwrap_or_default(); - let mut local_crates = Vec::new(); - for &crate_num in tcx.crates(()) { - let name = tcx.crate_name(crate_num); - let name = name.as_str(); - if local_crate_names.iter().any(|local_name| local_name == name) { - local_crates.push(crate_num); - } - } - local_crates -} - pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true". In two's complement, // -1 has all its bits set to one and `from_int` will truncate or diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fadbdf5cea99..1482ca0c345a 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -580,8 +580,8 @@ pub struct MiriMachine<'tcx> { /// Equivalent setting as RUST_BACKTRACE on encountering an error. pub(crate) backtrace_style: BacktraceStyle, - /// Crates which are considered local for the purposes of error reporting. - pub(crate) local_crates: Vec, + /// Crates which are considered user-relevant for the purposes of error reporting. + pub(crate) user_relevant_crates: Vec, /// Mapping extern static names to their pointer. extern_statics: FxHashMap, @@ -684,7 +684,7 @@ impl<'tcx> MiriMachine<'tcx> { genmc_ctx: Option>, ) -> Self { let tcx = layout_cx.tcx(); - let local_crates = helpers::get_local_crates(tcx); + let user_relevant_crates = Self::get_user_relevant_crates(tcx, config); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { @@ -774,7 +774,7 @@ impl<'tcx> MiriMachine<'tcx> { string_cache: Default::default(), exported_symbols_cache: FxHashMap::default(), backtrace_style: config.backtrace_style, - local_crates, + user_relevant_crates, extern_statics: FxHashMap::default(), rng: RefCell::new(rng), allocator: (!config.native_lib.is_empty()) @@ -865,6 +865,29 @@ impl<'tcx> MiriMachine<'tcx> { symbols } + /// Retrieve the list of user-relevant crates based on MIRI_LOCAL_CRATES as set by cargo-miri, + /// and extra crates set in the config. + fn get_user_relevant_crates(tcx: TyCtxt<'_>, config: &MiriConfig) -> Vec { + // Convert the local crate names from the passed-in config into CrateNums so that they can + // be looked up quickly during execution + let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") + .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::>()) + .unwrap_or_default(); + let mut local_crates = Vec::new(); + for &crate_num in tcx.crates(()) { + let name = tcx.crate_name(crate_num); + let name = name.as_str(); + if local_crate_names + .iter() + .chain(&config.user_relevant_crates) + .any(|local_name| local_name == name) + { + local_crates.push(crate_num); + } + } + local_crates + } + pub(crate) fn late_init( ecx: &mut MiriInterpCx<'tcx>, config: &MiriConfig, @@ -889,7 +912,7 @@ impl<'tcx> MiriMachine<'tcx> { /// Check whether the stack frame that this `FrameInfo` refers to is part of a local crate. pub(crate) fn is_local(&self, frame: &FrameInfo<'_>) -> bool { let def_id = frame.instance.def_id(); - def_id.is_local() || self.local_crates.contains(&def_id.krate) + def_id.is_local() || self.user_relevant_crates.contains(&def_id.krate) } /// Called when the interpreter is going to shut down abnormally, such as due to a Ctrl-C. @@ -1006,7 +1029,7 @@ impl VisitProvenance for MiriMachine<'_> { string_cache: _, exported_symbols_cache: _, backtrace_style: _, - local_crates: _, + user_relevant_crates: _, rng: _, allocator: _, tracked_alloc_ids: _,