Skip to content

Commit 3c3ae2c

Browse files
committed
Auto merge of #111867 - RalfJung:miri, r=RalfJung
update Miri
2 parents 80380ca + a238793 commit 3c3ae2c

File tree

19 files changed

+148
-49
lines changed

19 files changed

+148
-49
lines changed

Cargo.lock

+29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ smallvec = "1.7"
2929
# for more information.
3030
rustc-workspace-hack = "1.0.0"
3131
measureme = "10.0.0"
32+
ctrlc = "3.2.5"
3233

3334
[target.'cfg(unix)'.dependencies]
3435
libc = "0.2"

cargo-miri/src/arg.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ impl<'s, I: Iterator<Item = Cow<'s, str>>> Iterator for ArgSplitFlagValue<'_, I>
4040
if arg == "--" {
4141
// Stop searching at `--`.
4242
self.args = None;
43-
return None;
43+
// But yield the `--` so that it does not get lost!
44+
return Some(Err(Cow::Borrowed("--")));
4445
}
4546
// These branches cannot be merged if we want to avoid the allocation in the `Borrowed` branch.
4647
match &arg {
@@ -79,9 +80,8 @@ impl<'a, I: Iterator<Item = String> + 'a> ArgSplitFlagValue<'a, I> {
7980
) -> impl Iterator<Item = Result<String, String>> + 'a {
8081
ArgSplitFlagValue::new(args.map(Cow::Owned), name).map(|x| {
8182
match x {
82-
Ok(Cow::Owned(s)) => Ok(s),
83-
Err(Cow::Owned(s)) => Err(s),
84-
_ => panic!("iterator converted owned to borrowed"),
83+
Ok(s) => Ok(s.into_owned()),
84+
Err(s) => Err(s.into_owned()),
8585
}
8686
})
8787
}

cargo-miri/src/phases.rs

+27-25
Original file line numberDiff line numberDiff line change
@@ -113,30 +113,17 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
113113
};
114114
let metadata = get_cargo_metadata();
115115
let mut cmd = cargo();
116-
cmd.arg(cargo_cmd);
117-
118-
// Forward all arguments before `--` other than `--target-dir` and its value to Cargo.
119-
// (We want to *change* the target-dir value, so we must not forward it.)
120-
let mut target_dir = None;
121-
for arg in ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir") {
122-
match arg {
123-
Ok(value) => {
124-
if target_dir.is_some() {
125-
show_error!("`--target-dir` is provided more than once");
126-
}
127-
target_dir = Some(value.into());
128-
}
129-
Err(arg) => {
130-
cmd.arg(arg);
131-
}
132-
}
116+
cmd.arg(&cargo_cmd);
117+
// In nextest we have to also forward the main `verb`.
118+
if cargo_cmd == "nextest" {
119+
cmd.arg(
120+
args.next()
121+
.unwrap_or_else(|| show_error!("`cargo miri nextest` expects a verb (e.g. `run`)")),
122+
);
133123
}
134-
// Detect the target directory if it's not specified via `--target-dir`.
135-
// (`cargo metadata` does not support `--target-dir`, that's why we have to handle this ourselves.)
136-
let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone());
137-
// Set `--target-dir` to `miri` inside the original target directory.
138-
target_dir.push("miri");
139-
cmd.arg("--target-dir").arg(target_dir);
124+
// We set the following flags *before* forwarding more arguments.
125+
// This is needed to fix <https://github.com/rust-lang/miri/issues/2829>: cargo will stop
126+
// interpreting things as flags when it sees the first positional argument.
140127

141128
// Make sure the build target is explicitly set.
142129
// This is needed to make the `target.runner` settings do something,
@@ -154,8 +141,23 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
154141
cmd.arg("--config")
155142
.arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']"));
156143

157-
// Forward all further arguments after `--` to cargo.
158-
cmd.arg("--").args(args);
144+
// Set `--target-dir` to `miri` inside the original target directory.
145+
let mut target_dir = match get_arg_flag_value("--target-dir") {
146+
Some(dir) => PathBuf::from(dir),
147+
None => metadata.target_directory.clone().into_std_path_buf(),
148+
};
149+
target_dir.push("miri");
150+
cmd.arg("--target-dir").arg(target_dir);
151+
152+
// *After* we set all the flags that need setting, forward everything else. Make sure to skip
153+
// `--target-dir` (which would otherwise be set twice).
154+
for arg in
155+
ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir").filter_map(Result::err)
156+
{
157+
cmd.arg(arg);
158+
}
159+
// Forward all further arguments (not consumed by `ArgSplitFlagValue`) to cargo.
160+
cmd.args(args);
159161

160162
// Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation,
161163
// i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
69fef92ab2f287f072b66fb7b4f62c8bb4acba43
1+
8b4b20836b832e91aa605a2faf5e2a55190202c8

src/concurrency/thread.rs

+17
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::cell::RefCell;
44
use std::collections::hash_map::Entry;
55
use std::num::TryFromIntError;
6+
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
67
use std::task::Poll;
78
use std::time::{Duration, SystemTime};
89

@@ -1012,8 +1013,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10121013
/// Run the core interpreter loop. Returns only when an interrupt occurs (an error or program
10131014
/// termination).
10141015
fn run_threads(&mut self) -> InterpResult<'tcx, !> {
1016+
static SIGNALED: AtomicBool = AtomicBool::new(false);
1017+
ctrlc::set_handler(move || {
1018+
// Indicate that we have ben signaled to stop. If we were already signaled, exit
1019+
// immediately. In our interpreter loop we try to consult this value often, but if for
1020+
// whatever reason we don't get to that check or the cleanup we do upon finding that
1021+
// this bool has become true takes a long time, the exit here will promptly exit the
1022+
// process on the second Ctrl-C.
1023+
if SIGNALED.swap(true, Relaxed) {
1024+
std::process::exit(1);
1025+
}
1026+
})
1027+
.unwrap();
10151028
let this = self.eval_context_mut();
10161029
loop {
1030+
if SIGNALED.load(Relaxed) {
1031+
this.machine.handle_abnormal_termination();
1032+
std::process::exit(1);
1033+
}
10171034
match this.machine.threads.schedule(&this.machine.clock)? {
10181035
SchedulingAction::ExecuteStep => {
10191036
if !this.step()? {

src/machine.rs

+9
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,15 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
713713
let def_id = frame.instance.def_id();
714714
def_id.is_local() || self.local_crates.contains(&def_id.krate)
715715
}
716+
717+
/// Called when the interpreter is going to shut down abnormally, such as due to a Ctrl-C.
718+
pub(crate) fn handle_abnormal_termination(&mut self) {
719+
// All strings in the profile data are stored in a single string table which is not
720+
// written to disk until the profiler is dropped. If the interpreter exits without dropping
721+
// the profiler, it is not possible to interpret the profile data and all measureme tools
722+
// will panic when given the file.
723+
drop(self.profiler.take());
724+
}
716725
}
717726

718727
impl VisitTags for MiriMachine<'_, '_> {

src/shims/backtrace.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
102102
let ptr_layout = this.layout_of(ptr_ty)?;
103103

104104
for (i, ptr) in ptrs.into_iter().enumerate() {
105-
let offset = ptr_layout.size * i.try_into().unwrap();
105+
let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap();
106106

107107
let op_place = buf_place.offset(offset, ptr_layout, this)?;
108108

src/shims/foreign_items.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
166166
dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| {
167167
// We add 1 to the number because that's what rustc also does everywhere it
168168
// calls `CrateNum::new`...
169-
#[allow(clippy::integer_arithmetic)]
169+
#[allow(clippy::arithmetic_side_effects)]
170170
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
171171
}),
172172
) {
@@ -707,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
707707
.position(|&c| c == val)
708708
{
709709
let idx = u64::try_from(idx).unwrap();
710-
#[allow(clippy::integer_arithmetic)] // idx < num, so this never wraps
710+
#[allow(clippy::arithmetic_side_effects)] // idx < num, so this never wraps
711711
let new_ptr = ptr.offset(Size::from_bytes(num - idx - 1), this)?;
712712
this.write_pointer(new_ptr, dest)?;
713713
} else {
@@ -916,10 +916,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
916916
let a = this.read_scalar(a)?.to_u64()?;
917917
let b = this.read_scalar(b)?.to_u64()?;
918918

919-
#[allow(clippy::integer_arithmetic)]
919+
#[allow(clippy::arithmetic_side_effects)]
920920
// adding two u64 and a u8 cannot wrap in a u128
921921
let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b);
922-
#[allow(clippy::integer_arithmetic)] // it's a u128, we can shift by 64
922+
#[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64
923923
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
924924

925925
let c_out_field = this.place_field(dest, 0)?;

src/shims/intrinsics/simd.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
563563
let (op, op_len) = this.operand_to_simd(op)?;
564564
let bitmask_len = op_len.max(8);
565565

566-
assert!(dest.layout.ty.is_integral());
566+
// Returns either an unsigned integer or array of `u8`.
567+
assert!(
568+
dest.layout.ty.is_integral()
569+
|| matches!(dest.layout.ty.kind(), ty::Array(elemty, _) if elemty == &this.tcx.types.u8)
570+
);
567571
assert!(bitmask_len <= 64);
568572
assert_eq!(bitmask_len, dest.layout.size.bits());
569573
let op_len = u32::try_from(op_len).unwrap();
@@ -577,7 +581,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
577581
.unwrap();
578582
}
579583
}
580-
this.write_int(res, dest)?;
584+
// We have to force the place type to be an int so that we can write `res` into it.
585+
let mut dest = this.force_allocation(dest)?;
586+
dest.layout = this.machine.layouts.uint(dest.layout.size).unwrap();
587+
this.write_int(res, &dest.into())?;
581588
}
582589

583590
name => throw_unsup_format!("unimplemented intrinsic: `simd_{name}`"),
@@ -605,7 +612,7 @@ fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
605612
assert!(idx < vec_len);
606613
match endianness {
607614
Endian::Little => idx,
608-
#[allow(clippy::integer_arithmetic)] // idx < vec_len
615+
#[allow(clippy::arithmetic_side_effects)] // idx < vec_len
609616
Endian::Big => vec_len - 1 - idx, // reverse order of bits
610617
}
611618
}

src/shims/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![warn(clippy::integer_arithmetic)]
1+
#![warn(clippy::arithmetic_side_effects)]
22

33
mod backtrace;
44
#[cfg(target_os = "linux")]

src/shims/time.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
108108
Ok(0)
109109
}
110110

111-
#[allow(non_snake_case, clippy::integer_arithmetic)]
111+
#[allow(non_snake_case, clippy::arithmetic_side_effects)]
112112
fn GetSystemTimeAsFileTime(
113113
&mut self,
114114
LPFILETIME_op: &OpTy<'tcx, Provenance>,

src/shims/tls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<'tcx> Default for TlsData<'tcx> {
5656
impl<'tcx> TlsData<'tcx> {
5757
/// Generate a new TLS key with the given destructor.
5858
/// `max_size` determines the integer size the key has to fit in.
59-
#[allow(clippy::integer_arithmetic)]
59+
#[allow(clippy::arithmetic_side_effects)]
6060
pub fn create_tls_key(
6161
&mut self,
6262
dtor: Option<ty::Instance<'tcx>>,

src/shims/unix/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ pub struct DirHandler {
458458
}
459459

460460
impl DirHandler {
461-
#[allow(clippy::integer_arithmetic)]
461+
#[allow(clippy::arithmetic_side_effects)]
462462
fn insert_new(&mut self, read_dir: ReadDir) -> u64 {
463463
let id = self.next_id;
464464
self.next_id += 1;

src/shims/unix/linux/sync.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ pub fn futex<'tcx>(
247247
// before doing the syscall.
248248
this.atomic_fence(AtomicFenceOrd::SeqCst)?;
249249
let mut n = 0;
250-
#[allow(clippy::integer_arithmetic)]
250+
#[allow(clippy::arithmetic_side_effects)]
251251
for _ in 0..val {
252252
if let Some(thread) = this.futex_wake(addr_usize, bitset) {
253253
this.unblock_thread(thread);

src/shims/windows/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
219219
.copied()
220220
.scan(Size::ZERO, |a, x| {
221221
let res = Some(*a);
222-
*a += x;
222+
*a = a.checked_add(x, this).unwrap();
223223
res
224224
})
225225
.collect();

src/shims/windows/handle.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl Handle {
6262
let floor_log2 = variant_count.ilog2();
6363

6464
// we need to add one for non powers of two to compensate for the difference
65-
#[allow(clippy::integer_arithmetic)] // cannot overflow
65+
#[allow(clippy::arithmetic_side_effects)] // cannot overflow
6666
if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 }
6767
}
6868

@@ -87,7 +87,7 @@ impl Handle {
8787

8888
// packs the data into the lower `data_size` bits
8989
// and packs the discriminant right above the data
90-
#[allow(clippy::integer_arithmetic)] // cannot overflow
90+
#[allow(clippy::arithmetic_side_effects)] // cannot overflow
9191
return discriminant << data_size | data;
9292
}
9393

@@ -106,11 +106,11 @@ impl Handle {
106106
let data_size = u32::BITS.checked_sub(disc_size).unwrap();
107107

108108
// the lower `data_size` bits of this mask are 1
109-
#[allow(clippy::integer_arithmetic)] // cannot overflow
109+
#[allow(clippy::arithmetic_side_effects)] // cannot overflow
110110
let data_mask = 2u32.pow(data_size) - 1;
111111

112112
// the discriminant is stored right above the lower `data_size` bits
113-
#[allow(clippy::integer_arithmetic)] // cannot overflow
113+
#[allow(clippy::arithmetic_side_effects)] // cannot overflow
114114
let discriminant = handle >> data_size;
115115

116116
// the data is stored in the lower `data_size` bits

test-cargo-miri/run-test.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ def test_cargo_miri_run():
108108
env={'MIRITESTVAR': "wrongval"}, # changing the env var causes a rebuild (re-runs build.rs),
109109
# so keep it set
110110
)
111+
# This also covers passing arguments without `--`: Cargo will forward unused positional arguments to the program.
111112
test("`cargo miri run` (with arguments and target)",
112-
cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"', r'he\\llo\"world'],
113+
cargo_miri("run") + ["--bin", "cargo-miri-test", "hello world", '"hello world"', r'he\\llo\"world'],
113114
"run.args.stdout.ref", "run.args.stderr.ref",
114115
)
115116
test("`cargo miri r` (subcrate, no isolation)",

0 commit comments

Comments
 (0)