Skip to content

Commit 21b23de

Browse files
committed
Auto merge of #1048 - Aaron1011:panic-rustup, r=<try>
Rustup for panic changes This gets Miri working again, but doesn't actually implement unwinding
2 parents 2bdf163 + f41c720 commit 21b23de

File tree

7 files changed

+108
-40
lines changed

7 files changed

+108
-40
lines changed

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
56237d75b4271a8a2e0f47d86ea76ebf6d966152
1+
a333eed7fc0c903df9d6befcfb40af02148bf255

src/bin/cargo-miri.rs

+90-31
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::{PathBuf, Path};
66
use std::process::Command;
77
use std::ops::Not;
88

9-
const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17);
9+
const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 18);
1010

1111
const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri
1212
@@ -80,7 +80,36 @@ fn get_arg_flag_value(name: &str) -> Option<String> {
8080
}
8181
}
8282

83-
fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
83+
fn is_build_dep(mut args: impl Iterator<Item = String>) -> bool {
84+
args.any(|arg| arg.starts_with("--emit=") && arg.contains("link"))
85+
}
86+
87+
// Returns whether or not Cargo invoked the wrapper (this binary) to compile
88+
// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run')
89+
// Right now, this is an awful hack that checks several different pieces of information
90+
// to try to figure out if the crate being compiled is the right one.
91+
// Ideally, Cargo would set en environment variable indicating whether or
92+
// not the wrapper is being invoked on the target crate.
93+
// For now, this is the best we can do
94+
fn is_target_crate(is_build_script: bool) -> bool {
95+
// Cargo sets this to the directory containing the manifest of the crate
96+
// the wrapper is being invoekd to compile. This should be unique
97+
// across the entire build (except for build scripts, which we handle below).
98+
// We cannot check the crate name, since this may not be unique
99+
// (e.g. if the build contains multiple versions of the same crate,
100+
// or the same crate from multiple sources)
101+
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").ok();
102+
103+
// The manifest directory for our target crate. This is set by `cargo-miri`
104+
// (the original invoation by the user) by using `cargo_metadata` to locate
105+
// the manifest.
106+
let expected_dir = std::env::var("MIRI_MAGIC_DIR").expect("MIRI_MAGIC_DIR not set!");
107+
108+
manifest_dir == Some(expected_dir) && !is_build_script
109+
110+
}
111+
112+
fn read_cargo_metadata() -> (impl Iterator<Item=cargo_metadata::Target>, String) {
84113
// We need to get the manifest, and then the metadata, to enumerate targets.
85114
let manifest_path = get_arg_flag_value("--manifest-path").map(|m|
86115
Path::new(&m).canonicalize().unwrap()
@@ -119,7 +148,7 @@ fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
119148
let package = metadata.packages.remove(package_index);
120149

121150
// Finally we got the list of targets to build
122-
package.targets.into_iter()
151+
(package.targets.into_iter(), metadata.workspace_root.to_string_lossy().to_string())
123152
}
124153

125154
/// Returns the path to the `miri` binary
@@ -266,7 +295,7 @@ fn setup(ask_user: bool) {
266295
show_error(format!("Your xargo is too old; please upgrade to the latest version"))
267296
}
268297
let mut cmd = cargo();
269-
cmd.args(&["install", "xargo", "-f"]);
298+
cmd.args(&["install", "-f", "--git", "https://github.com./Aaron1011/xargo", "--branch", "feature/cargo-mode"]);
270299
ask_to_run(cmd, ask_user, "install a recent enough xargo");
271300
}
272301

@@ -294,6 +323,7 @@ fn setup(ask_user: bool) {
294323
// The interesting bit: Xargo.toml
295324
File::create(dir.join("Xargo.toml")).unwrap()
296325
.write_all(br#"
326+
cargo_mode = "check"
297327
[dependencies.std]
298328
default_features = false
299329
# We need the `panic_unwind` feature because we use the `unwind` panic strategy.
@@ -318,7 +348,12 @@ path = "lib.rs"
318348
let target = get_arg_flag_value("--target");
319349
let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
320350
let mut command = xargo();
321-
command.arg("build").arg("-q");
351+
// This may seen somewhat suprising - we are 'building' libstd
352+
// by running (the equivalent of) `cargo check`. It turns out
353+
// that `cargo check` has exactly the behavior that we want:
354+
// it emits crate metadata (including MIR) without running any
355+
// codegen.
356+
command.arg("check").arg("-q");
322357
command.current_dir(&dir);
323358
command.env("RUSTFLAGS", miri::miri_default_args().join(" "));
324359
command.env("XARGO_HOME", dir.to_str().unwrap());
@@ -336,6 +371,7 @@ path = "lib.rs"
336371
show_error(format!("Failed to run xargo"));
337372
}
338373

374+
339375
// That should be it! But we need to figure out where xargo built stuff.
340376
// Unfortunately, it puts things into a different directory when the
341377
// architecture matches the host.
@@ -404,8 +440,10 @@ fn in_cargo_miri() {
404440
return;
405441
}
406442

443+
let (targets, root_dir) = read_cargo_metadata();
444+
407445
// Now run the command.
408-
for target in list_targets() {
446+
for target in targets {
409447
let mut args = std::env::args().skip(skip);
410448
let kind = target.kind.get(0).expect(
411449
"badly formatted cargo metadata: target::kind is an empty array",
@@ -414,7 +452,7 @@ fn in_cargo_miri() {
414452
// change to add additional arguments. `FLAGS` is set to identify
415453
// this target. The user gets to control what gets actually passed to Miri.
416454
let mut cmd = cargo();
417-
cmd.arg("rustc");
455+
cmd.arg("check");
418456
match (subcommand, kind.as_str()) {
419457
(MiriCommand::Run, "bin") => {
420458
// FIXME: we just run all the binaries here.
@@ -441,14 +479,17 @@ fn in_cargo_miri() {
441479
}
442480
cmd.arg(arg);
443481
}
444-
// Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the
445-
// user flags to be able to identify them later. "cargo rustc" adds more stuff after this,
446-
// so we have to mark both the beginning and the end.
447-
cmd
448-
.arg("--")
449-
.arg("cargo-miri-marker-begin")
450-
.args(args)
451-
.arg("cargo-miri-marker-end");
482+
483+
let mut prefixed_args = String::new();
484+
for arg in args {
485+
prefixed_args += &arg.len().to_string();
486+
prefixed_args.push(';');
487+
prefixed_args += &arg;
488+
}
489+
490+
cmd.env("MIRI_MAGIC_ARGS", prefixed_args);
491+
cmd.env("MIRI_MAGIC_DIR", root_dir.clone());
492+
452493
let path = std::env::current_exe().expect("current executable path invalid");
453494
cmd.env("RUSTC_WRAPPER", path);
454495
if verbose {
@@ -470,27 +511,45 @@ fn in_cargo_miri() {
470511
fn inside_cargo_rustc() {
471512
let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT");
472513

514+
473515
let rustc_args = std::env::args().skip(2); // skip `cargo rustc`
474-
let mut args: Vec<String> = rustc_args
475-
.chain(Some("--sysroot".to_owned()))
476-
.chain(Some(sysroot))
477-
.collect();
478-
args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
516+
517+
518+
eprintln!("cargo rustc env: {:?}", std::env::vars().collect::<Vec<_>>());
519+
520+
let in_build_script = is_build_dep(std::env::args().skip(2));
521+
522+
523+
let mut args = if in_build_script {
524+
rustc_args.collect()
525+
} else {
526+
let mut args: Vec<String> = rustc_args
527+
.chain(Some("--sysroot".to_owned()))
528+
.chain(Some(sysroot))
529+
.collect();
530+
args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
531+
args
532+
};
479533

480534
// See if we can find the `cargo-miri` markers. Those only get added to the binary we want to
481535
// run. They also serve to mark the user-defined arguments, which we have to move all the way
482536
// to the end (they get added somewhere in the middle).
483-
let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") {
484-
let end = args
485-
.iter()
486-
.position(|arg| arg == "cargo-miri-marker-end")
487-
.expect("cannot find end marker");
488-
// These mark the user arguments. We remove the first and last as they are the markers.
489-
let mut user_args = args.drain(begin..=end);
490-
assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin");
491-
assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end");
492-
// Collect the rest and add it back at the end.
493-
let mut user_args = user_args.collect::<Vec<String>>();
537+
let needs_miri = if is_target_crate(in_build_script) {
538+
let raw_args = std::env::var("MIRI_MAGIC_ARGS").expect("Missing magic!");
539+
let mut user_args = vec![];
540+
let mut slice = raw_args.as_str();
541+
loop {
542+
match slice.find(';') {
543+
Some(pos) => {
544+
let len: usize = slice[..(pos)].parse().unwrap();
545+
let arg = slice[(pos+1)..=(pos+len)].to_string();
546+
user_args.push(arg);
547+
slice = &slice[(pos+len+1)..];
548+
},
549+
None => break
550+
}
551+
}
552+
494553
args.append(&mut user_args);
495554
// Run this in Miri.
496555
true

src/eval.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
213213
};
214214
e.print_backtrace();
215215
if let Some(frame) = ecx.stack().last() {
216-
let block = &frame.body.basic_blocks()[frame.block];
216+
let block = &frame.body.basic_blocks()[frame.block.unwrap()];
217217
let span = if frame.stmt < block.statements.len() {
218218
block.statements[frame.stmt].source_info.span
219219
} else {

src/machine.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
173173
args: &[OpTy<'tcx, Tag>],
174174
dest: Option<PlaceTy<'tcx, Tag>>,
175175
ret: Option<mir::BasicBlock>,
176+
_unwind: Option<mir::BasicBlock>,
176177
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
177178
ecx.find_fn(instance, args, dest, ret)
178179
}
@@ -194,8 +195,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
194195
span: Span,
195196
instance: ty::Instance<'tcx>,
196197
args: &[OpTy<'tcx, Tag>],
197-
dest: PlaceTy<'tcx, Tag>,
198+
dest: Option<PlaceTy<'tcx, Tag>>,
199+
_ret: Option<mir::BasicBlock>,
200+
_unwind: Option<mir::BasicBlock>
198201
) -> InterpResult<'tcx> {
202+
let dest = match dest {
203+
Some(dest) => dest,
204+
None => throw_ub!(Unreachable)
205+
};
199206
ecx.call_intrinsic(span, instance, args, dest)
200207
}
201208

@@ -353,13 +360,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
353360
fn stack_pop(
354361
ecx: &mut InterpCx<'mir, 'tcx, Self>,
355362
extra: stacked_borrows::CallId,
356-
) -> InterpResult<'tcx> {
357-
Ok(ecx
363+
_unwinding: bool
364+
) -> InterpResult<'tcx, StackPopInfo> {
365+
ecx
358366
.memory
359367
.extra
360368
.stacked_borrows
361369
.borrow_mut()
362-
.end_call(extra))
370+
.end_call(extra);
371+
Ok(StackPopInfo::Normal)
363372
}
364373

365374
#[inline(always)]

src/shims/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
335335
mir,
336336
Some(ret_place),
337337
// Directly return to caller.
338-
StackPopCleanup::Goto(Some(ret)),
338+
StackPopCleanup::Goto { ret: Some(ret), unwind: None },
339339
)?;
340340
let mut args = this.frame().body.args_iter();
341341

src/shims/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2222
dest: PlaceTy<'tcx, Tag>,
2323
) -> InterpResult<'tcx> {
2424
let this = self.eval_context_mut();
25-
if this.emulate_intrinsic(span, instance, args, dest)? {
25+
if this.emulate_intrinsic(span, instance, args, Some(dest))? {
2626
return Ok(());
2727
}
2828
let tcx = &{this.tcx.tcx};

src/shims/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2727
);
2828

2929
// First, run the common hooks also supported by CTFE.
30-
if this.hook_fn(instance, args, dest)? {
30+
if this.hook_panic_fn(instance, args, dest)? {
3131
this.goto_block(ret)?;
3232
return Ok(None);
3333
}

0 commit comments

Comments
 (0)