Skip to content

Commit 4116585

Browse files
committed
many-seeds: add flag to keep going even after we found a failing seed
1 parent 0f49f0f commit 4116585

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

src/tools/miri/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ environment variable. We first document the most relevant and most commonly used
323323
This is useful to find bugs that only occur under particular interleavings of concurrent threads,
324324
or that otherwise depend on non-determinism. If the `<from>` part is skipped, it defaults to `0`.
325325
Can be used without a value; in that case the range defaults to `0..64`.
326+
* `-Zmiri-many-seeds-keep-going` tells Miri to really try all the seeds in the given range, even if
327+
a failing seed has already been found. This is useful to determine which fraction of seeds fails.
326328
* `-Zmiri-num-cpus` states the number of available CPUs to be reported by miri. By default, the
327329
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
328330
any way.

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

+22-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use std::ops::Range;
3030
use std::path::PathBuf;
3131
use std::str::FromStr;
3232
use std::sync::Arc;
33-
use std::sync::atomic::{AtomicBool, Ordering};
33+
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
3434

3535
use miri::{
3636
BacktraceStyle, BorrowTrackerMethod, MiriConfig, ProvenanceMode, RetagFields, ValidationMode,
@@ -59,11 +59,16 @@ use tracing::debug;
5959

6060
struct MiriCompilerCalls {
6161
miri_config: Option<MiriConfig>,
62-
many_seeds: Option<Range<u32>>,
62+
many_seeds: Option<ManySeedsConfig>,
63+
}
64+
65+
struct ManySeedsConfig {
66+
seeds: Range<u32>,
67+
keep_going: bool,
6368
}
6469

6570
impl MiriCompilerCalls {
66-
fn new(miri_config: MiriConfig, many_seeds: Option<Range<u32>>) -> Self {
71+
fn new(miri_config: MiriConfig, many_seeds: Option<ManySeedsConfig>) -> Self {
6772
Self { miri_config: Some(miri_config), many_seeds }
6873
}
6974
}
@@ -176,19 +181,24 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
176181

177182
if let Some(many_seeds) = self.many_seeds.take() {
178183
assert!(config.seed.is_none());
179-
sync::par_for_each_in(many_seeds, |seed| {
184+
let exit_code = sync::IntoDynSyncSend(AtomicI32::new(rustc_driver::EXIT_SUCCESS));
185+
sync::par_for_each_in(many_seeds.seeds, |seed| {
180186
let mut config = config.clone();
181187
config.seed = Some(seed.into());
182188
eprintln!("Trying seed: {seed}");
183189
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
184190
.unwrap_or(rustc_driver::EXIT_FAILURE);
185191
if return_code != rustc_driver::EXIT_SUCCESS {
186192
eprintln!("FAILING SEED: {seed}");
187-
tcx.dcx().abort_if_errors(); // exits with a different error message
188-
std::process::exit(return_code);
193+
if !many_seeds.keep_going {
194+
// `abort_if_errors` would actually not stop, since `par_for_each` waits for the
195+
// rest of the to finish, so we just exit immediately.
196+
std::process::exit(return_code);
197+
}
198+
exit_code.store(return_code, Ordering::Relaxed);
189199
}
190200
});
191-
std::process::exit(rustc_driver::EXIT_SUCCESS);
201+
std::process::exit(exit_code.0.into_inner());
192202
} else {
193203
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
194204
.unwrap_or_else(|| {
@@ -500,6 +510,7 @@ fn main() {
500510

501511
// Parse our arguments and split them across `rustc` and `miri`.
502512
let mut many_seeds: Option<Range<u32>> = None;
513+
let mut many_seeds_keep_going = false;
503514
let mut miri_config = MiriConfig::default();
504515
miri_config.env = env_snapshot;
505516

@@ -611,6 +622,8 @@ fn main() {
611622
many_seeds = Some(range);
612623
} else if arg == "-Zmiri-many-seeds" {
613624
many_seeds = Some(0..64);
625+
} else if arg == "-Zmiri-many-seeds-keep-going" {
626+
many_seeds_keep_going = true;
614627
} else if let Some(_param) = arg.strip_prefix("-Zmiri-env-exclude=") {
615628
show_error!(
616629
"`-Zmiri-env-exclude` has been removed; unset env vars before starting Miri instead"
@@ -736,6 +749,8 @@ fn main() {
736749
std::thread::available_parallelism().map_or(1, |n| n.get())
737750
));
738751
}
752+
let many_seeds =
753+
many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going });
739754

740755
debug!("rustc arguments: {:?}", rustc_args);
741756
debug!("crate arguments: {:?}", miri_config.args);

0 commit comments

Comments
 (0)