Skip to content

Commit 48897d0

Browse files
authored
Merge pull request #766 from RalfJung/sysroot
Sysroot consistency check
2 parents f090362 + 81debbd commit 48897d0

File tree

5 files changed

+81
-66
lines changed

5 files changed

+81
-66
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,12 @@ Several `-Z` flags are relevant for Miri:
250250

251251
Moreover, Miri recognizes some environment variables:
252252

253-
* `MIRI_SYSROOT` (recognized by `miri`, `cargo miri` and the test suite)
254-
indicates the sysroot to use.
255-
* `MIRI_TARGET` (recognized by the test suite) indicates which target
253+
* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during
254+
Miri executions, also [see above][testing-miri].
255+
* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite)
256+
indicates the sysroot to use. To do the same thing with `miri`
257+
directly, use the `--sysroot` flag.
258+
* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target
256259
architecture to test against. `miri` and `cargo miri` accept the `--target`
257260
flag for the same purpose.
258261

miri

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ build_sysroot() {
5555
cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@"
5656
# Call again, to just set env var.
5757
eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@")
58-
export MIRI_SYSROOT
5958
}
6059

6160
# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account
@@ -73,7 +72,7 @@ find_sysroot() {
7372
build_sysroot --target "$MIRI_TEST_TARGET"
7473
else
7574
# Assume we have a proper host libstd in $SYSROOT.
76-
true
75+
MIRI_SYSROOT="$SYSROOT"
7776
fi
7877
else
7978
# A normal toolchain. We have to build a sysroot either way.
@@ -83,6 +82,7 @@ find_sysroot() {
8382
build_sysroot
8483
fi
8584
fi
85+
export MIRI_SYSROOT
8686
}
8787

8888
## Main
@@ -140,7 +140,7 @@ run|run-debug)
140140
cargo build $CARGO_BUILD_FLAGS
141141
find_sysroot
142142
# Then run the actual command.
143-
exec cargo run $CARGO_BUILD_FLAGS "$@"
143+
exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@"
144144
;;
145145
*)
146146
echo "Unknown command: $COMMAND"

src/bin/cargo-miri.rs

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,41 @@ fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
119119
package.targets.into_iter()
120120
}
121121

122+
/// Returns the path to the `miri` binary
123+
fn find_miri() -> PathBuf {
124+
let mut path = std::env::current_exe().expect("current executable path invalid");
125+
path.set_file_name("miri");
126+
path
127+
}
128+
129+
/// Make sure that the `miri` and `rustc` binary are from the same sysroot.
130+
/// This can be violated e.g. when miri is locally built and installed with a different
131+
/// toolchain than what is used when `cargo miri` is run.
132+
fn test_sysroot_consistency() {
133+
fn get_sysroot(mut cmd: Command) -> PathBuf {
134+
let out = cmd.arg("--print").arg("sysroot")
135+
.output().expect("Failed to run rustc to get sysroot info");
136+
assert!(out.status.success(), "Bad status code when getting sysroot info");
137+
let sysroot = out.stdout.lines().nth(0)
138+
.expect("didn't get at least one line for the sysroot").unwrap();
139+
PathBuf::from(sysroot).canonicalize()
140+
.expect("Failed to canonicalize sysroot")
141+
}
142+
143+
let rustc_sysroot = get_sysroot(Command::new("rustc"));
144+
let miri_sysroot = get_sysroot(Command::new(find_miri()));
145+
146+
if rustc_sysroot != miri_sysroot {
147+
show_error(format!(
148+
"miri was built for a different sysroot than the rustc in your current toolchain.\n\
149+
Make sure you use the same toolchain to run miri that you used to build it!\n\
150+
rustc sysroot: `{}`\n\
151+
miri sysroot: `{}`",
152+
rustc_sysroot.display(), miri_sysroot.display()
153+
));
154+
}
155+
}
156+
122157
fn xargo_version() -> Option<(u32, u32, u32)> {
123158
let out = Command::new("xargo").arg("--version").output().ok()?;
124159
if !out.status.success() {
@@ -265,11 +300,11 @@ path = "lib.rs"
265300
Some(target) => target == rustc_version::version_meta().unwrap().host,
266301
};
267302
let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
268-
std::env::set_var("MIRI_SYSROOT", &sysroot);
303+
std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags
269304
if print_env {
270305
println!("MIRI_SYSROOT={}", sysroot.display());
271306
} else if !ask_user {
272-
println!("A libstd for Miri is now available in `{}`", sysroot.display());
307+
println!("A libstd for Miri is now available in `{}`.", sysroot.display());
273308
}
274309
}
275310

@@ -313,6 +348,9 @@ fn in_cargo_miri() {
313348
};
314349
let verbose = has_arg_flag("-v");
315350

351+
// Some basic sanity checks
352+
test_sysroot_consistency();
353+
316354
// We always setup.
317355
let ask = subcommand != MiriCommand::Setup;
318356
setup(ask);
@@ -385,38 +423,13 @@ fn in_cargo_miri() {
385423
}
386424

387425
fn inside_cargo_rustc() {
388-
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
389-
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
390-
let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
391-
sysroot
392-
} else if let (Some(home), Some(toolchain)) = (home, toolchain) {
393-
format!("{}/toolchains/{}", home, toolchain)
394-
} else {
395-
option_env!("RUST_SYSROOT")
396-
.map(|s| s.to_owned())
397-
.or_else(|| {
398-
Command::new("rustc")
399-
.arg("--print")
400-
.arg("sysroot")
401-
.output()
402-
.ok()
403-
.and_then(|out| String::from_utf8(out.stdout).ok())
404-
.map(|s| s.trim().to_owned())
405-
})
406-
.expect("need to specify `RUST_SYSROOT` env var during miri compilation, or use rustup or multirust")
407-
};
426+
let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT");
408427

409-
// This conditional check for the `--sysroot` flag is there so that users can call `cargo-miri`
410-
// directly without having to pass `--sysroot` or anything.
411-
let rustc_args = std::env::args().skip(2);
412-
let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
413-
rustc_args.collect()
414-
} else {
415-
rustc_args
416-
.chain(Some("--sysroot".to_owned()))
417-
.chain(Some(sys_root))
418-
.collect()
419-
};
428+
let rustc_args = std::env::args().skip(2); // skip `cargo rustc`
429+
let mut args: Vec<String> = rustc_args
430+
.chain(Some("--sysroot".to_owned()))
431+
.chain(Some(sysroot))
432+
.collect();
420433
args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
421434

422435
// See if we can find the `cargo-miri` markers. Those only get added to the binary we want to
@@ -441,9 +454,7 @@ fn inside_cargo_rustc() {
441454
};
442455

443456
let mut command = if needs_miri {
444-
let mut path = std::env::current_exe().expect("current executable path invalid");
445-
path.set_file_name("miri");
446-
Command::new(path)
457+
Command::new(find_miri())
447458
} else {
448459
Command::new("rustc")
449460
};

src/bin/miri.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,9 @@ fn init_late_loggers() {
100100
}
101101
}
102102

103-
fn find_sysroot() -> String {
104-
if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
105-
return sysroot;
106-
}
107-
103+
/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
104+
/// Should be a compile-time constant.
105+
fn compile_time_sysroot() -> String {
108106
// Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
109107
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
110108
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
@@ -167,12 +165,16 @@ fn main() {
167165
}
168166
}
169167

170-
// Determine sysroot and let rustc know about it.
171-
let sysroot_flag = String::from("--sysroot");
168+
// Determine sysroot.
169+
let sysroot_flag = "--sysroot".to_string();
172170
if !rustc_args.contains(&sysroot_flag) {
171+
// We need to *always* set a --sysroot, as the "default" rustc uses is
172+
// somewhere in the directory miri was built in.
173+
// If no --sysroot is given, fall back to env vars that are read at *compile-time*.
173174
rustc_args.push(sysroot_flag);
174-
rustc_args.push(find_sysroot());
175+
rustc_args.push(compile_time_sysroot());
175176
}
177+
176178
// Finally, add the default flags all the way in the beginning, but after the binary name.
177179
rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));
178180

tests/compiletest.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,15 @@ fn rustc_lib_path() -> PathBuf {
2525
option_env!("RUSTC_LIB_PATH").unwrap().into()
2626
}
2727

28-
fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp {
28+
fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
29+
// Some flags we always want.
30+
flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
31+
flags.push("--edition 2018".to_owned());
32+
if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
33+
flags.push(format!("--sysroot {}", sysroot));
34+
}
35+
36+
// The rest of the configuration.
2937
let mut config = compiletest::Config::default().tempdir();
3038
config.mode = mode.parse().expect("Invalid mode");
3139
config.rustc_path = miri_path();
@@ -35,7 +43,10 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp {
3543
}
3644
config.filter = env::args().nth(1);
3745
config.host = get_host();
38-
config
46+
config.src_base = PathBuf::from(path);
47+
config.target = target.to_owned();
48+
config.target_rustcflags = Some(flags.join(" "));
49+
compiletest::run_tests(&config);
3950
}
4051

4152
fn compile_fail(path: &str, target: &str, opt: bool) {
@@ -48,20 +59,14 @@ fn compile_fail(path: &str, target: &str, opt: bool) {
4859
).green().bold());
4960

5061
let mut flags = Vec::new();
51-
flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
52-
flags.push("--edition 2018".to_owned());
5362
if opt {
5463
// Optimizing too aggressivley makes UB detection harder, but test at least
5564
// the default value.
5665
// FIXME: Opt level 3 ICEs during stack trace generation.
5766
flags.push("-Zmir-opt-level=1".to_owned());
5867
}
5968

60-
let mut config = mk_config("compile-fail");
61-
config.src_base = PathBuf::from(path);
62-
config.target = target.to_owned();
63-
config.target_rustcflags = Some(flags.join(" "));
64-
compiletest::run_tests(&config);
69+
run_tests("compile-fail", path, target, flags);
6570
}
6671

6772
fn miri_pass(path: &str, target: &str, opt: bool) {
@@ -74,17 +79,11 @@ fn miri_pass(path: &str, target: &str, opt: bool) {
7479
).green().bold());
7580

7681
let mut flags = Vec::new();
77-
flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
78-
flags.push("--edition 2018".to_owned());
7982
if opt {
8083
flags.push("-Zmir-opt-level=3".to_owned());
8184
}
8285

83-
let mut config = mk_config("ui");
84-
config.src_base = PathBuf::from(path);
85-
config.target = target.to_owned();
86-
config.target_rustcflags = Some(flags.join(" "));
87-
compiletest::run_tests(&config);
86+
run_tests("ui", path, target, flags);
8887
}
8988

9089
fn get_host() -> String {

0 commit comments

Comments
 (0)