Skip to content

Commit 1898c34

Browse files
committed
Auto merge of #103571 - RalfJung:miri, r=RalfJung
update Miri r? `@ghost`
2 parents 36285c5 + 6ce5226 commit 1898c34

25 files changed

+234
-92
lines changed

src/tools/miri/README.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -538,15 +538,23 @@ extern "Rust" {
538538
fn miri_start_panic(payload: *mut u8) -> !;
539539

540540
/// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer
541-
/// points to. This is only useful as an input to `miri_print_stacks`, and it is a separate call because
541+
/// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort.
542+
///
543+
/// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because
542544
/// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation.
545+
/// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so
546+
/// inherits all of its instability.
543547
fn miri_get_alloc_id(ptr: *const ()) -> u64;
544548

545549
/// Miri-provided extern function to print (from the interpreter, not the program) the contents of all
546-
/// borrow stacks in an allocation. The format of what this emits is unstable and may change at any time.
547-
/// In particular, users should be aware that Miri will periodically attempt to garbage collect the
548-
/// contents of all stacks. Callers of this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
549-
fn miri_print_stacks(alloc_id: u64);
550+
/// borrow stacks in an allocation. The leftmost tag is the bottom of the stack.
551+
/// The format of what this emits is unstable and may change at any time. In particular, users should be
552+
/// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of
553+
/// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
554+
///
555+
/// This function is extremely unstable. At any time the format of its output may change, its signature may
556+
/// change, or it may be removed entirely.
557+
fn miri_print_borrow_stacks(alloc_id: u64);
550558

551559
/// Miri-provided extern function to print (from the interpreter, not the
552560
/// program) the contents of a section of program memory, as bytes. Bytes

src/tools/miri/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ fn main() {
44
// Re-export the TARGET environment variable so it can
55
// be accessed by miri.
66
let target = std::env::var("TARGET").unwrap();
7-
println!("cargo:rustc-env=TARGET={}", target);
7+
println!("cargo:rustc-env=TARGET={target}");
88
}

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Examples:
3434
"#;
3535

3636
fn show_help() {
37-
println!("{}", CARGO_MIRI_HELP);
37+
println!("{CARGO_MIRI_HELP}");
3838
}
3939

4040
fn show_version() {
@@ -52,7 +52,7 @@ fn forward_patched_extern_arg(args: &mut impl Iterator<Item = String>, cmd: &mut
5252
let path = args.next().expect("`--extern` should be followed by a filename");
5353
if let Some(lib) = path.strip_suffix(".rlib") {
5454
// If this is an rlib, make it an rmeta.
55-
cmd.arg(format!("{}.rmeta", lib));
55+
cmd.arg(format!("{lib}.rmeta"));
5656
} else {
5757
// Some other extern file (e.g. a `.so`). Forward unchanged.
5858
cmd.arg(path);
@@ -336,7 +336,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
336336
"[cargo-miri rustc inside rustdoc] captured input:\n{}",
337337
std::str::from_utf8(&env.stdin).unwrap()
338338
);
339-
eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd);
339+
eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{cmd:?}");
340340
}
341341

342342
exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display()));
@@ -374,7 +374,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
374374
val.push("metadata");
375375
}
376376
}
377-
cmd.arg(format!("{}={}", emit_flag, val.join(",")));
377+
cmd.arg(format!("{emit_flag}={}", val.join(",")));
378378
} else if arg == "--extern" {
379379
// Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files:
380380
// https://github.com/rust-lang/miri/issues/1705
@@ -535,7 +535,7 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
535535
// Run it.
536536
debug_cmd("[cargo-miri runner]", verbose, &cmd);
537537
match phase {
538-
RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)),
538+
RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{binary}.stdin")),
539539
RunnerPhase::Cargo => exec(cmd),
540540
}
541541
}

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub fn escape_for_toml(s: &str) -> String {
8383
// We want to surround this string in quotes `"`. So we first escape all quotes,
8484
// and also all backslashes (that are used to escape quotes).
8585
let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#);
86-
format!("\"{}\"", s)
86+
format!("\"{s}\"")
8787
}
8888

8989
/// Returns the path to the `miri` binary
@@ -175,7 +175,7 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) {
175175
let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some();
176176
if ask && !is_ci {
177177
let mut buf = String::new();
178-
print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text);
178+
print!("I will run `{cmd:?}` to {text}. Proceed? [Y/n] ");
179179
io::stdout().flush().unwrap();
180180
io::stdin().read_line(&mut buf).unwrap();
181181
match buf.trim().to_lowercase().as_ref() {
@@ -185,10 +185,10 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) {
185185
a => show_error!("invalid answer `{}`", a),
186186
};
187187
} else {
188-
eprintln!("Running `{:?}` to {}.", cmd, text);
188+
eprintln!("Running `{cmd:?}` to {text}.");
189189
}
190190

191-
if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() {
191+
if cmd.status().unwrap_or_else(|_| panic!("failed to execute {cmd:?}")).success().not() {
192192
show_error!("failed to {}", text);
193193
}
194194
}
@@ -276,12 +276,12 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) {
276276
// Print only what has been changed for this `cmd`.
277277
for (var, val) in cmd.get_envs() {
278278
if let Some(val) = val {
279-
writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap();
279+
writeln!(out, "{}={val:?} \\", var.to_string_lossy()).unwrap();
280280
} else {
281281
writeln!(out, "--unset={}", var.to_string_lossy()).unwrap();
282282
}
283283
}
284284
}
285285
write!(out, "{cmd:?}").unwrap();
286-
eprintln!("{}", out);
286+
eprintln!("{out}");
287287
}

src/tools/miri/rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b1ab3b738ac718da74cd4aa0bb7f362d0adbdf84
1+
85d089b41e2a0c0f07ab34f6c5a7c451389f25e6

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) {
192192
if log::Level::from_str(&var).is_ok() {
193193
env::set_var(
194194
"RUSTC_LOG",
195-
&format!(
195+
format!(
196196
"rustc_middle::mir::interpret={0},rustc_const_eval::interpret={0}",
197197
var
198198
),
@@ -243,7 +243,7 @@ fn host_sysroot() -> Option<String> {
243243
)
244244
}
245245
}
246-
format!("{}/toolchains/{}", home, toolchain)
246+
format!("{home}/toolchains/{toolchain}")
247247
}
248248
_ => option_env!("RUST_SYSROOT")
249249
.unwrap_or_else(|| {
@@ -330,7 +330,7 @@ fn main() {
330330
} else if crate_kind == "host" {
331331
false
332332
} else {
333-
panic!("invalid `MIRI_BE_RUSTC` value: {:?}", crate_kind)
333+
panic!("invalid `MIRI_BE_RUSTC` value: {crate_kind:?}")
334334
};
335335

336336
// We cannot use `rustc_driver::main` as we need to adjust the CLI arguments.

src/tools/miri/src/concurrency/thread.rs

+1
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
870870
this.machine.threads.active_thread_stack_mut()
871871
}
872872

873+
/// Set the name of the current thread. The buffer must not include the null terminator.
873874
#[inline]
874875
fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {
875876
let this = self.eval_context_mut();

src/tools/miri/src/concurrency/vector_clock.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ mod tests {
399399

400400
//Test partial_cmp
401401
let compare = l.partial_cmp(&r);
402-
assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}", l, r);
402+
assert_eq!(compare, o, "Invalid comparison\n l: {l:?}\n r: {r:?}");
403403
let alt_compare = r.partial_cmp(&l);
404404
assert_eq!(
405405
alt_compare,

src/tools/miri/src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ pub fn report_error<'tcx, 'mir>(
263263
msg.insert(0, e.to_string());
264264
report_msg(
265265
DiagLevel::Error,
266-
&if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() },
266+
&if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() },
267267
msg,
268268
vec![],
269269
helps,

src/tools/miri/src/helpers.rs

+61-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod convert;
22

33
use std::cmp;
4+
use std::iter;
45
use std::mem;
56
use std::num::NonZeroUsize;
67
use std::time::Duration;
@@ -107,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
107108
/// Gets an instance for a path.
108109
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
109110
self.try_resolve_path(path)
110-
.unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path))
111+
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
111112
}
112113

113114
/// Evaluates the scalar at the specified path. Returns Some(val)
@@ -505,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
505506
RejectOpWith::WarningWithoutBacktrace => {
506507
this.tcx
507508
.sess
508-
.warn(&format!("{} was made to return an error due to isolation", op_name));
509+
.warn(format!("{op_name} was made to return an error due to isolation"));
509510
Ok(())
510511
}
511512
RejectOpWith::Warning => {
@@ -735,6 +736,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
735736
})
736737
}
737738

739+
/// Read a sequence of bytes until the first null terminator.
738740
fn read_c_str<'a>(&'a self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, &'a [u8]>
739741
where
740742
'tcx: 'a,
@@ -761,6 +763,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
761763
this.read_bytes_ptr_strip_provenance(ptr, len)
762764
}
763765

766+
/// Helper function to write a sequence of bytes with an added null-terminator, which is what
767+
/// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
768+
/// to write if `size` is not large enough to fit the contents of `c_str` plus a null
769+
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
770+
/// string length returned does include the null terminator.
771+
fn write_c_str(
772+
&mut self,
773+
c_str: &[u8],
774+
ptr: Pointer<Option<Provenance>>,
775+
size: u64,
776+
) -> InterpResult<'tcx, (bool, u64)> {
777+
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
778+
// terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
779+
let string_length = u64::try_from(c_str.len()).unwrap();
780+
let string_length = string_length.checked_add(1).unwrap();
781+
if size < string_length {
782+
return Ok((false, string_length));
783+
}
784+
self.eval_context_mut()
785+
.write_bytes_ptr(ptr, c_str.iter().copied().chain(iter::once(0u8)))?;
786+
Ok((true, string_length))
787+
}
788+
789+
/// Read a sequence of u16 until the first null terminator.
764790
fn read_wide_str(&self, mut ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
765791
let this = self.eval_context_ref();
766792
let size2 = Size::from_bytes(2);
@@ -783,6 +809,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
783809
Ok(wchars)
784810
}
785811

812+
/// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what
813+
/// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
814+
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
815+
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
816+
/// string length returned does include the null terminator. Length is measured in units of
817+
/// `u16.`
818+
fn write_wide_str(
819+
&mut self,
820+
wide_str: &[u16],
821+
ptr: Pointer<Option<Provenance>>,
822+
size: u64,
823+
) -> InterpResult<'tcx, (bool, u64)> {
824+
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
825+
// 0x0000 terminator to memory would cause an out-of-bounds access.
826+
let string_length = u64::try_from(wide_str.len()).unwrap();
827+
let string_length = string_length.checked_add(1).unwrap();
828+
if size < string_length {
829+
return Ok((false, string_length));
830+
}
831+
832+
// Store the UTF-16 string.
833+
let size2 = Size::from_bytes(2);
834+
let this = self.eval_context_mut();
835+
let mut alloc = this
836+
.get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())?
837+
.unwrap(); // not a ZST, so we will get a result
838+
for (offset, wchar) in wide_str.iter().copied().chain(iter::once(0x0000)).enumerate() {
839+
let offset = u64::try_from(offset).unwrap();
840+
alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?;
841+
}
842+
Ok((true, string_length))
843+
}
844+
786845
/// Check that the ABI is what we expect.
787846
fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
788847
if self.eval_context_ref().machine.enforce_abi && abi != exp_abi {

src/tools/miri/src/machine.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,12 @@ impl interpret::Provenance for Provenance {
191191
Provenance::Concrete { alloc_id, sb } => {
192192
// Forward `alternate` flag to `alloc_id` printing.
193193
if f.alternate() {
194-
write!(f, "[{:#?}]", alloc_id)?;
194+
write!(f, "[{alloc_id:#?}]")?;
195195
} else {
196-
write!(f, "[{:?}]", alloc_id)?;
196+
write!(f, "[{alloc_id:?}]")?;
197197
}
198198
// Print Stacked Borrows tag.
199-
write!(f, "{:?}", sb)?;
199+
write!(f, "{sb:?}")?;
200200
}
201201
Provenance::Wildcard => {
202202
write!(f, "[wildcard]")?;

src/tools/miri/src/range_map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl<T> RangeMap<T> {
4040
let mut left = 0usize; // inclusive
4141
let mut right = self.v.len(); // exclusive
4242
loop {
43-
debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset);
43+
debug_assert!(left < right, "find_offset: offset {offset} is out-of-bounds");
4444
let candidate = left.checked_add(right).unwrap() / 2;
4545
let elem = &self.v[candidate];
4646
if offset < elem.range.start {

src/tools/miri/src/shims/foreign_items.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
321321
return Ok(Some(body));
322322
}
323323

324-
this.handle_unsupported(format!("can't call foreign function: {}", link_name))?;
324+
this.handle_unsupported(format!("can't call foreign function: {link_name}"))?;
325325
return Ok(None);
326326
}
327327
}
@@ -420,10 +420,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
420420
"miri_get_alloc_id" => {
421421
let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
422422
let ptr = this.read_pointer(ptr)?;
423-
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr)?;
423+
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
424+
err_machine_stop!(TerminationInfo::Abort(
425+
format!("pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}")
426+
))
427+
})?;
424428
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
425429
}
426-
"miri_print_stacks" => {
430+
"miri_print_borrow_stacks" => {
427431
let [id] = this.check_shim(abi, Abi::Rust, link_name, args)?;
428432
let id = this.read_scalar(id)?.to_u64()?;
429433
if let Some(id) = std::num::NonZeroU64::new(id) {

src/tools/miri/src/shims/os_str.rs

+2-31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::borrow::Cow;
22
use std::ffi::{OsStr, OsString};
3-
use std::iter;
43
use std::path::{Path, PathBuf};
54

65
#[cfg(unix)]
@@ -9,7 +8,6 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt};
98
use std::os::windows::ffi::{OsStrExt, OsStringExt};
109

1110
use rustc_middle::ty::layout::LayoutOf;
12-
use rustc_target::abi::{Align, Size};
1311

1412
use crate::*;
1513

@@ -100,16 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10098
size: u64,
10199
) -> InterpResult<'tcx, (bool, u64)> {
102100
let bytes = os_str_to_bytes(os_str)?;
103-
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
104-
// terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
105-
let string_length = u64::try_from(bytes.len()).unwrap();
106-
let string_length = string_length.checked_add(1).unwrap();
107-
if size < string_length {
108-
return Ok((false, string_length));
109-
}
110-
self.eval_context_mut()
111-
.write_bytes_ptr(ptr, bytes.iter().copied().chain(iter::once(0u8)))?;
112-
Ok((true, string_length))
101+
self.eval_context_mut().write_c_str(bytes, ptr, size)
113102
}
114103

115104
/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what
@@ -140,25 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
140129
}
141130

142131
let u16_vec = os_str_to_u16vec(os_str)?;
143-
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
144-
// 0x0000 terminator to memory would cause an out-of-bounds access.
145-
let string_length = u64::try_from(u16_vec.len()).unwrap();
146-
let string_length = string_length.checked_add(1).unwrap();
147-
if size < string_length {
148-
return Ok((false, string_length));
149-
}
150-
151-
// Store the UTF-16 string.
152-
let size2 = Size::from_bytes(2);
153-
let this = self.eval_context_mut();
154-
let mut alloc = this
155-
.get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())?
156-
.unwrap(); // not a ZST, so we will get a result
157-
for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() {
158-
let offset = u64::try_from(offset).unwrap();
159-
alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?;
160-
}
161-
Ok((true, string_length))
132+
self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)
162133
}
163134

164135
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.

0 commit comments

Comments
 (0)