Skip to content

Commit 60fef6b

Browse files
borspoliorcetics
authored andcommitted
Auto merge of rust-lang#134784 - RalfJung:miri-sync, r=RalfJung
Miri subtree update r? `@ghost`
2 parents 7d7153e + 60e3bf4 commit 60fef6b

25 files changed

+868
-719
lines changed

src/tools/miri/CONTRIBUTING.md

+9
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ Miri comes with a few benchmarks; you can run `./miri bench` to run them with th
212212
Miri. Note: this will run `./miri install` as a side-effect. Also requires `hyperfine` to be
213213
installed (`cargo install hyperfine`).
214214

215+
To compare the benchmark results with a baseline, do the following:
216+
- Before applying your changes, run `./miri bench --save-baseline=baseline.json`.
217+
- Then do your changes.
218+
- Then run `./miri bench --load-baseline=baseline.json`; the results will include
219+
a comparison with the baseline.
220+
221+
You can run only some of the benchmarks by listing them, e.g. `./miri bench mse`.
222+
The names refer to the folders in `bench-cargo-miri`.
223+
215224
## Configuring `rust-analyzer`
216225

217226
To configure `rust-analyzer` and the IDE for working on Miri, copy one of the provided

src/tools/miri/README.md

+19-7
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,14 @@ Certain parts of the execution are picked randomly by Miri, such as the exact ba
160160
allocations are stored at and the interleaving of concurrently executing threads. Sometimes, it can
161161
be useful to explore multiple different execution, e.g. to make sure that your code does not depend
162162
on incidental "super-alignment" of new allocations and to test different thread interleavings.
163-
This can be done with the `--many-seeds` flag:
163+
This can be done with the `-Zmiri-many-seeds` flag:
164164

165165
```
166-
cargo miri test --many-seeds # tries the seeds in 0..64
167-
cargo miri test --many-seeds=0..16
166+
MIRIFLAGS="-Zmiri-many-seeds" cargo miri test # tries the seeds in 0..64
167+
MIRIFLAGS="-Zmiri-many-seeds=0..16" cargo miri test
168168
```
169169

170-
The default of 64 different seeds is quite slow, so you probably want to specify a smaller range.
170+
The default of 64 different seeds can be quite slow, so you often want to specify a smaller range.
171171

172172
### Running Miri on CI
173173

@@ -294,9 +294,10 @@ environment variable. We first document the most relevant and most commonly used
294294
will always fail and `0.0` means it will never fail. Note that setting it to
295295
`1.0` will likely cause hangs, since it means programs using
296296
`compare_exchange_weak` cannot make progress.
297-
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
297+
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
298298
the program has access to host resources such as environment variables, file
299299
systems, and randomness.
300+
This overwrites a previous `-Zmiri-isolation-error`.
300301
* `-Zmiri-disable-leak-backtraces` disables backtraces reports for memory leaks. By default, a
301302
backtrace is captured for every allocation when it is created, just in case it leaks. This incurs
302303
some memory overhead to store data that is almost never used. This flag is implied by
@@ -317,6 +318,15 @@ environment variable. We first document the most relevant and most commonly used
317318
execution with a "permission denied" error being returned to the program.
318319
`warn` prints a full backtrace each time that happens; `warn-nobacktrace` is less
319320
verbose and shown at most once per operation. `hide` hides the warning entirely.
321+
This overwrites a previous `-Zmiri-disable-isolation`.
322+
* `-Zmiri-many-seeds=[<from>]..<to>` runs the program multiple times with different seeds for Miri's
323+
RNG. With different seeds, Miri will make different choices to resolve non-determinism such as the
324+
order in which concurrent threads are scheduled, or the exact addresses assigned to allocations.
325+
This is useful to find bugs that only occur under particular interleavings of concurrent threads,
326+
or that otherwise depend on non-determinism. If the `<from>` part is skipped, it defaults to `0`.
327+
Can be used without a value; in that case the range defaults to `0..64`.
328+
* `-Zmiri-many-seeds-keep-going` tells Miri to really try all the seeds in the given range, even if
329+
a failing seed has already been found. This is useful to determine which fraction of seeds fails.
320330
* `-Zmiri-num-cpus` states the number of available CPUs to be reported by miri. By default, the
321331
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
322332
any way.
@@ -339,8 +349,8 @@ environment variable. We first document the most relevant and most commonly used
339349
can increase test coverage by running Miri multiple times with different seeds.
340350
* `-Zmiri-strict-provenance` enables [strict
341351
provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that
342-
casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance
343-
that cannot be used for any memory access.
352+
casting an integer to a pointer will stop execution because the provenance of the pointer
353+
cannot be determined.
344354
* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is
345355
checked by casting the pointer to an integer, and making sure that is a multiple of the alignment.
346356
This can lead to cases where a program passes the alignment check by pure chance, because things
@@ -429,6 +439,8 @@ to Miri failing to detect cases of undefined behavior in a program.
429439
of Rust will be stricter than Tree Borrows. In other words, if you use Tree Borrows,
430440
even if your code is accepted today, it might be declared UB in the future.
431441
This is much less likely with Stacked Borrows.
442+
Using Tree Borrows currently implies `-Zmiri-strict-provenance` because integer-to-pointer
443+
casts are not supported in this mode, but that may change in the future.
432444
* `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k.
433445
`4` is default for most targets. This value should always be a power of 2 and nonzero.
434446
* `-Zmiri-unique-is-unique` performs additional aliasing checks for `core::ptr::Unique` to ensure

src/tools/miri/cargo-miri/src/phases.rs

+78-121
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Implements the various phases of `cargo miri run/test`.
22
3+
use std::env;
34
use std::fs::{self, File};
4-
use std::io::{BufReader, Write};
5+
use std::io::BufReader;
56
use std::path::{Path, PathBuf};
67
use std::process::Command;
7-
use std::{env, thread};
88

99
use rustc_version::VersionMeta;
1010

@@ -24,10 +24,7 @@ Subcommands:
2424
clean Clean the Miri cache & target directory
2525
2626
The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
27-
Furthermore, the following extra flags and environment variables are recognized for `run` and `test`:
28-
29-
--many-seeds[=from..to] Run the program/tests many times with different seeds in the given range.
30-
The range defaults to `0..64`.
27+
Furthermore, the following environment variables are recognized for `run` and `test`:
3128
3229
MIRIFLAGS Extra flags to pass to the Miri driver. Use this to pass `-Zmiri-...` flags.
3330
@@ -41,8 +38,6 @@ Examples:
4138
4239
";
4340

44-
const DEFAULT_MANY_SEEDS: &str = "0..64";
45-
4641
fn show_help() {
4742
println!("{CARGO_MIRI_HELP}");
4843
}
@@ -182,17 +177,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
182177
let target_dir = get_target_dir(&metadata);
183178
cmd.arg("--target-dir").arg(target_dir);
184179

185-
// Store many-seeds argument.
186-
let mut many_seeds = None;
187180
// *After* we set all the flags that need setting, forward everything else. Make sure to skip
188-
// `--target-dir` (which would otherwise be set twice) and `--many-seeds` (which is our flag, not cargo's).
181+
// `--target-dir` (which would otherwise be set twice).
189182
for arg in
190183
ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir").filter_map(Result::err)
191184
{
192-
if arg == "--many-seeds" {
193-
many_seeds = Some(DEFAULT_MANY_SEEDS.to_owned());
194-
} else if let Some(val) = arg.strip_prefix("--many-seeds=") {
195-
many_seeds = Some(val.to_owned());
185+
if arg == "--many-seeds" || arg.starts_with("--many-seeds=") {
186+
show_error!(
187+
"ERROR: the `--many-seeds` flag has been removed from cargo-miri; use MIRIFLAGS=-Zmiri-many-seeds instead"
188+
);
196189
} else {
197190
cmd.arg(arg);
198191
}
@@ -249,9 +242,6 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
249242
// Forward some crucial information to our own re-invocations.
250243
cmd.env("MIRI_SYSROOT", miri_sysroot);
251244
cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata));
252-
if let Some(many_seeds) = many_seeds {
253-
cmd.env("MIRI_MANY_SEEDS", many_seeds);
254-
}
255245
if verbose > 0 {
256246
cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose.
257247
}
@@ -407,14 +397,11 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
407397

408398
// Alter the `-o` parameter so that it does not overwrite the JSON file we stored above.
409399
let mut args = env.args;
410-
let mut out_filename = None;
411400
for i in 0..args.len() {
412401
if args[i] == "-o" {
413-
out_filename = Some(args[i + 1].clone());
414402
args[i + 1].push_str(".miri");
415403
}
416404
}
417-
let out_filename = out_filename.expect("rustdoc must pass `-o`");
418405

419406
cmd.args(&args);
420407
cmd.env("MIRI_BE_RUSTC", "target");
@@ -427,7 +414,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
427414
eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{cmd:?}");
428415
}
429416

430-
exec_with_pipe(cmd, &env.stdin, format!("{out_filename}.stdin"));
417+
exec_with_pipe(cmd, &env.stdin);
431418
}
432419

433420
return;
@@ -589,111 +576,81 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
589576
}
590577
};
591578

592-
let many_seeds = env::var("MIRI_MANY_SEEDS");
593-
run_many_seeds(many_seeds.ok(), |seed| {
594-
let mut cmd = miri();
595-
596-
// Set missing env vars. We prefer build-time env vars over run-time ones; see
597-
// <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
598-
for (name, val) in &info.env {
599-
// `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
600-
// the program is being run, that jobserver no longer exists (cargo only runs the jobserver
601-
// for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
602-
// Also see <https://github.com/rust-lang/rust/pull/113730>.
603-
if name == "CARGO_MAKEFLAGS" {
604-
continue;
605-
}
606-
if let Some(old_val) = env::var_os(name) {
607-
if *old_val == *val {
608-
// This one did not actually change, no need to re-set it.
609-
// (This keeps the `debug_cmd` below more manageable.)
610-
continue;
611-
} else if verbose > 0 {
612-
eprintln!(
613-
"[cargo-miri runner] Overwriting run-time env var {name:?}={old_val:?} with build-time value {val:?}"
614-
);
615-
}
616-
}
617-
cmd.env(name, val);
618-
}
579+
let mut cmd = miri();
619580

620-
if phase != RunnerPhase::Rustdoc {
621-
// Set the sysroot. Not necessary in rustdoc, where we already set the sysroot in
622-
// `phase_rustdoc`. rustdoc will forward that flag when invoking rustc (i.e., us), so the
623-
// flag is present in `info.args`.
624-
cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap());
581+
// Set missing env vars. We prefer build-time env vars over run-time ones; see
582+
// <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
583+
for (name, val) in &info.env {
584+
// `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
585+
// the program is being run, that jobserver no longer exists (cargo only runs the jobserver
586+
// for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
587+
// Also see <https://github.com/rust-lang/rust/pull/113730>.
588+
if name == "CARGO_MAKEFLAGS" {
589+
continue;
625590
}
626-
// Forward rustc arguments.
627-
// We need to patch "--extern" filenames because we forced a check-only
628-
// build without cargo knowing about that: replace `.rlib` suffix by
629-
// `.rmeta`.
630-
// We also need to remove `--error-format` as cargo specifies that to be JSON,
631-
// but when we run here, cargo does not interpret the JSON any more. `--json`
632-
// then also needs to be dropped.
633-
let mut args = info.args.iter();
634-
while let Some(arg) = args.next() {
635-
if arg == "--extern" {
636-
forward_patched_extern_arg(&mut (&mut args).cloned(), &mut cmd);
637-
} else if let Some(suffix) = arg.strip_prefix("--error-format") {
638-
assert!(suffix.starts_with('='));
639-
// Drop this argument.
640-
} else if let Some(suffix) = arg.strip_prefix("--json") {
641-
assert!(suffix.starts_with('='));
642-
// Drop this argument.
643-
} else {
644-
cmd.arg(arg);
591+
if let Some(old_val) = env::var_os(name) {
592+
if *old_val == *val {
593+
// This one did not actually change, no need to re-set it.
594+
// (This keeps the `debug_cmd` below more manageable.)
595+
continue;
596+
} else if verbose > 0 {
597+
eprintln!(
598+
"[cargo-miri runner] Overwriting run-time env var {name:?}={old_val:?} with build-time value {val:?}"
599+
);
645600
}
646601
}
647-
// Respect `MIRIFLAGS`.
648-
if let Ok(a) = env::var("MIRIFLAGS") {
649-
let args = flagsplit(&a);
650-
cmd.args(args);
651-
}
652-
// Set the current seed.
653-
if let Some(seed) = seed {
654-
eprintln!("Trying seed: {seed}");
655-
cmd.arg(format!("-Zmiri-seed={seed}"));
656-
}
602+
cmd.env(name, val);
603+
}
657604

658-
// Then pass binary arguments.
659-
cmd.arg("--");
660-
cmd.args(&binary_args);
661-
662-
// Make sure we use the build-time working directory for interpreting Miri/rustc arguments.
663-
// But then we need to switch to the run-time one, which we instruct Miri to do by setting `MIRI_CWD`.
664-
cmd.current_dir(&info.current_dir);
665-
cmd.env("MIRI_CWD", env::current_dir().unwrap());
666-
667-
// Run it.
668-
debug_cmd("[cargo-miri runner]", verbose, &cmd);
669-
670-
match phase {
671-
RunnerPhase::Rustdoc => {
672-
cmd.stdin(std::process::Stdio::piped());
673-
// the warning is wrong, we have a `wait` inside the `scope` closure.
674-
let mut child = cmd.spawn().expect("failed to spawn process");
675-
let child_stdin = child.stdin.take().unwrap();
676-
// Write stdin in a background thread, as it may block.
677-
let exit_status = thread::scope(|s| {
678-
s.spawn(|| {
679-
let mut child_stdin = child_stdin;
680-
// Ignore failure, it is most likely due to the process having terminated.
681-
let _ = child_stdin.write_all(&info.stdin);
682-
});
683-
child.wait().expect("failed to run command")
684-
});
685-
if !exit_status.success() {
686-
std::process::exit(exit_status.code().unwrap_or(-1));
687-
}
688-
}
689-
RunnerPhase::Cargo => {
690-
let exit_status = cmd.status().expect("failed to run command");
691-
if !exit_status.success() {
692-
std::process::exit(exit_status.code().unwrap_or(-1));
693-
}
694-
}
605+
if phase != RunnerPhase::Rustdoc {
606+
// Set the sysroot. Not necessary in rustdoc, where we already set the sysroot in
607+
// `phase_rustdoc`. rustdoc will forward that flag when invoking rustc (i.e., us), so the
608+
// flag is present in `info.args`.
609+
cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap());
610+
}
611+
// Forward rustc arguments.
612+
// We need to patch "--extern" filenames because we forced a check-only
613+
// build without cargo knowing about that: replace `.rlib` suffix by
614+
// `.rmeta`.
615+
// We also need to remove `--error-format` as cargo specifies that to be JSON,
616+
// but when we run here, cargo does not interpret the JSON any more. `--json`
617+
// then also needs to be dropped.
618+
let mut args = info.args.iter();
619+
while let Some(arg) = args.next() {
620+
if arg == "--extern" {
621+
forward_patched_extern_arg(&mut (&mut args).cloned(), &mut cmd);
622+
} else if let Some(suffix) = arg.strip_prefix("--error-format") {
623+
assert!(suffix.starts_with('='));
624+
// Drop this argument.
625+
} else if let Some(suffix) = arg.strip_prefix("--json") {
626+
assert!(suffix.starts_with('='));
627+
// Drop this argument.
628+
} else {
629+
cmd.arg(arg);
695630
}
696-
});
631+
}
632+
// Respect `MIRIFLAGS`.
633+
if let Ok(a) = env::var("MIRIFLAGS") {
634+
let args = flagsplit(&a);
635+
cmd.args(args);
636+
}
637+
638+
// Then pass binary arguments.
639+
cmd.arg("--");
640+
cmd.args(&binary_args);
641+
642+
// Make sure we use the build-time working directory for interpreting Miri/rustc arguments.
643+
// But then we need to switch to the run-time one, which we instruct Miri to do by setting `MIRI_CWD`.
644+
cmd.current_dir(&info.current_dir);
645+
cmd.env("MIRI_CWD", env::current_dir().unwrap());
646+
647+
// Run it.
648+
debug_cmd("[cargo-miri runner]", verbose, &cmd);
649+
650+
match phase {
651+
RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin),
652+
RunnerPhase::Cargo => exec(cmd),
653+
}
697654
}
698655

699656
pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {

0 commit comments

Comments
 (0)