diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 81c4f5ffef4..5803a88c0e7 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -538,15 +538,23 @@ extern "Rust" { fn miri_start_panic(payload: *mut u8) -> !; /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer - /// points to. This is only useful as an input to `miri_print_stacks`, and it is a separate call because + /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort. + /// + /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation. + /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so + /// inherits all of its instability. fn miri_get_alloc_id(ptr: *const ()) -> u64; /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all - /// borrow stacks in an allocation. The format of what this emits is unstable and may change at any time. - /// In particular, users should be aware that Miri will periodically attempt to garbage collect the - /// contents of all stacks. Callers of this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. - fn miri_print_stacks(alloc_id: u64); + /// borrow stacks in an allocation. The leftmost tag is the bottom of the stack. + /// The format of what this emits is unstable and may change at any time. In particular, users should be + /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of + /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. + /// + /// This function is extremely unstable. At any time the format of its output may change, its signature may + /// change, or it may be removed entirely. + fn miri_print_borrow_stacks(alloc_id: u64); /// Miri-provided extern function to print (from the interpreter, not the /// program) the contents of a section of program memory, as bytes. Bytes diff --git a/src/tools/miri/build.rs b/src/tools/miri/build.rs index 37c626baab5..0977c0ba016 100644 --- a/src/tools/miri/build.rs +++ b/src/tools/miri/build.rs @@ -4,5 +4,5 @@ fn main() { // Re-export the TARGET environment variable so it can // be accessed by miri. let target = std::env::var("TARGET").unwrap(); - println!("cargo:rustc-env=TARGET={}", target); + println!("cargo:rustc-env=TARGET={target}"); } diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 0c1f039d6cc..22da80be902 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -34,7 +34,7 @@ "#; fn show_help() { - println!("{}", CARGO_MIRI_HELP); + println!("{CARGO_MIRI_HELP}"); } fn show_version() { @@ -52,7 +52,7 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut let path = args.next().expect("`--extern` should be followed by a filename"); if let Some(lib) = path.strip_suffix(".rlib") { // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", lib)); + cmd.arg(format!("{lib}.rmeta")); } else { // Some other extern file (e.g. a `.so`). Forward unchanged. cmd.arg(path); @@ -336,7 +336,7 @@ fn out_filename(prefix: &str, suffix: &str) -> PathBuf { "[cargo-miri rustc inside rustdoc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap() ); - eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); + eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{cmd:?}"); } exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); @@ -374,7 +374,7 @@ fn out_filename(prefix: &str, suffix: &str) -> PathBuf { val.push("metadata"); } } - cmd.arg(format!("{}={}", emit_flag, val.join(","))); + cmd.arg(format!("{emit_flag}={}", val.join(","))); } else if arg == "--extern" { // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: // https://github.com/rust-lang/miri/issues/1705 @@ -535,7 +535,7 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner // Run it. debug_cmd("[cargo-miri runner]", verbose, &cmd); match phase { - RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{binary}.stdin")), RunnerPhase::Cargo => exec(cmd), } } diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs index aabe5547e5c..60f39cb36ab 100644 --- a/src/tools/miri/cargo-miri/src/util.rs +++ b/src/tools/miri/cargo-miri/src/util.rs @@ -83,7 +83,7 @@ pub fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, // and also all backslashes (that are used to escape quotes). let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); - format!("\"{}\"", s) + format!("\"{s}\"") } /// Returns the path to the `miri` binary @@ -175,7 +175,7 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); if ask && !is_ci { let mut buf = String::new(); - print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); + print!("I will run `{cmd:?}` to {text}. Proceed? [Y/n] "); io::stdout().flush().unwrap(); io::stdin().read_line(&mut buf).unwrap(); match buf.trim().to_lowercase().as_ref() { @@ -185,10 +185,10 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { a => show_error!("invalid answer `{}`", a), }; } else { - eprintln!("Running `{:?}` to {}.", cmd, text); + eprintln!("Running `{cmd:?}` to {text}."); } - if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { + if cmd.status().unwrap_or_else(|_| panic!("failed to execute {cmd:?}")).success().not() { show_error!("failed to {}", text); } } @@ -276,12 +276,12 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { // Print only what has been changed for this `cmd`. for (var, val) in cmd.get_envs() { if let Some(val) = val { - writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); + writeln!(out, "{}={val:?} \\", var.to_string_lossy()).unwrap(); } else { writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); } } } write!(out, "{cmd:?}").unwrap(); - eprintln!("{}", out); + eprintln!("{out}"); } diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index eb0301bee2a..d0e98a8b0db 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -b1ab3b738ac718da74cd4aa0bb7f362d0adbdf84 +85d089b41e2a0c0f07ab34f6c5a7c451389f25e6 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 2e114c71d66..bd01ea655dd 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -192,7 +192,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { if log::Level::from_str(&var).is_ok() { env::set_var( "RUSTC_LOG", - &format!( + format!( "rustc_middle::mir::interpret={0},rustc_const_eval::interpret={0}", var ), @@ -243,7 +243,7 @@ fn host_sysroot() -> Option { ) } } - format!("{}/toolchains/{}", home, toolchain) + format!("{home}/toolchains/{toolchain}") } _ => option_env!("RUST_SYSROOT") .unwrap_or_else(|| { @@ -330,7 +330,7 @@ fn main() { } else if crate_kind == "host" { false } else { - panic!("invalid `MIRI_BE_RUSTC` value: {:?}", crate_kind) + panic!("invalid `MIRI_BE_RUSTC` value: {crate_kind:?}") }; // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 3432f10f7a9..ac5dcbf0f4f 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -870,6 +870,7 @@ fn active_thread_stack_mut( this.machine.threads.active_thread_stack_mut() } + /// Set the name of the current thread. The buffer must not include the null terminator. #[inline] fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index 32449f8eb18..e7e5b35ac2c 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -399,7 +399,7 @@ fn assert_order(l: &[VTimestamp], r: &[VTimestamp], o: Option) { //Test partial_cmp let compare = l.partial_cmp(&r); - assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}", l, r); + assert_eq!(compare, o, "Invalid comparison\n l: {l:?}\n r: {r:?}"); let alt_compare = r.partial_cmp(&l); assert_eq!( alt_compare, diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index ecfe0cd3f8a..ec81ffd3cd5 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -263,7 +263,7 @@ pub fn report_error<'tcx, 'mir>( msg.insert(0, e.to_string()); report_msg( DiagLevel::Error, - &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, + &if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() }, msg, vec![], helps, diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 15833fe42ad..f98727186c4 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1,6 +1,7 @@ pub mod convert; use std::cmp; +use std::iter; use std::mem; use std::num::NonZeroUsize; use std::time::Duration; @@ -107,7 +108,7 @@ fn try_resolve_path(&self, path: &[&str]) -> Option> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { self.try_resolve_path(path) - .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)) + .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}")) } /// Evaluates the scalar at the specified path. Returns Some(val) @@ -505,7 +506,7 @@ fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> Inter RejectOpWith::WarningWithoutBacktrace => { this.tcx .sess - .warn(&format!("{} was made to return an error due to isolation", op_name)); + .warn(format!("{op_name} was made to return an error due to isolation")); Ok(()) } RejectOpWith::Warning => { @@ -735,6 +736,7 @@ fn read_timespec( }) } + /// Read a sequence of bytes until the first null terminator. fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, @@ -761,6 +763,30 @@ fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'t this.read_bytes_ptr_strip_provenance(ptr, len) } + /// Helper function to write a sequence of bytes with an added null-terminator, which is what + /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `c_str` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does include the null terminator. + fn write_c_str( + &mut self, + c_str: &[u8], + ptr: Pointer>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null + // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. + let string_length = u64::try_from(c_str.len()).unwrap(); + let string_length = string_length.checked_add(1).unwrap(); + if size < string_length { + return Ok((false, string_length)); + } + self.eval_context_mut() + .write_bytes_ptr(ptr, c_str.iter().copied().chain(iter::once(0u8)))?; + Ok((true, string_length)) + } + + /// Read a sequence of u16 until the first null terminator. fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); @@ -783,6 +809,39 @@ fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'t Ok(wchars) } + /// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what + /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does include the null terminator. Length is measured in units of + /// `u16.` + fn write_wide_str( + &mut self, + wide_str: &[u16], + ptr: Pointer>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required + // 0x0000 terminator to memory would cause an out-of-bounds access. + let string_length = u64::try_from(wide_str.len()).unwrap(); + let string_length = string_length.checked_add(1).unwrap(); + if size < string_length { + return Ok((false, string_length)); + } + + // Store the UTF-16 string. + let size2 = Size::from_bytes(2); + let this = self.eval_context_mut(); + let mut alloc = this + .get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? + .unwrap(); // not a ZST, so we will get a result + for (offset, wchar) in wide_str.iter().copied().chain(iter::once(0x0000)).enumerate() { + let offset = u64::try_from(offset).unwrap(); + alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?; + } + Ok((true, string_length)) + } + /// Check that the ABI is what we expect. fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { if self.eval_context_ref().machine.enforce_abi && abi != exp_abi { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fc9a1170d29..e014e2db1e1 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -191,12 +191,12 @@ fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { Provenance::Concrete { alloc_id, sb } => { // Forward `alternate` flag to `alloc_id` printing. if f.alternate() { - write!(f, "[{:#?}]", alloc_id)?; + write!(f, "[{alloc_id:#?}]")?; } else { - write!(f, "[{:?}]", alloc_id)?; + write!(f, "[{alloc_id:?}]")?; } // Print Stacked Borrows tag. - write!(f, "{:?}", sb)?; + write!(f, "{sb:?}")?; } Provenance::Wildcard => { write!(f, "[wildcard]")?; diff --git a/src/tools/miri/src/range_map.rs b/src/tools/miri/src/range_map.rs index 4742a365ec3..c8ff06a3665 100644 --- a/src/tools/miri/src/range_map.rs +++ b/src/tools/miri/src/range_map.rs @@ -40,7 +40,7 @@ fn find_offset(&self, offset: u64) -> usize { let mut left = 0usize; // inclusive let mut right = self.v.len(); // exclusive loop { - debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); + debug_assert!(left < right, "find_offset: offset {offset} is out-of-bounds"); let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; if offset < elem.range.start { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index a49e6ba4ce3..1b3205aabc9 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -321,7 +321,7 @@ fn emulate_foreign_item( return Ok(Some(body)); } - this.handle_unsupported(format!("can't call foreign function: {}", link_name))?; + this.handle_unsupported(format!("can't call foreign function: {link_name}"))?; return Ok(None); } } @@ -420,10 +420,14 @@ fn emulate_foreign_item_by_name( "miri_get_alloc_id" => { let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr)?; + let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| { + err_machine_stop!(TerminationInfo::Abort( + format!("pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}") + )) + })?; this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } - "miri_print_stacks" => { + "miri_print_borrow_stacks" => { let [id] = this.check_shim(abi, Abi::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; if let Some(id) = std::num::NonZeroU64::new(id) { diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 407dab970ad..99b3605c601 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::ffi::{OsStr, OsString}; -use std::iter; use std::path::{Path, PathBuf}; #[cfg(unix)] @@ -9,7 +8,6 @@ use std::os::windows::ffi::{OsStrExt, OsStringExt}; use rustc_middle::ty::layout::LayoutOf; -use rustc_target::abi::{Align, Size}; use crate::*; @@ -100,16 +98,7 @@ fn write_os_str_to_c_str( size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null - // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - let string_length = u64::try_from(bytes.len()).unwrap(); - let string_length = string_length.checked_add(1).unwrap(); - if size < string_length { - return Ok((false, string_length)); - } - self.eval_context_mut() - .write_bytes_ptr(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; - Ok((true, string_length)) + self.eval_context_mut().write_c_str(bytes, ptr, size) } /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what @@ -140,25 +129,7 @@ fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { } let u16_vec = os_str_to_u16vec(os_str)?; - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required - // 0x0000 terminator to memory would cause an out-of-bounds access. - let string_length = u64::try_from(u16_vec.len()).unwrap(); - let string_length = string_length.checked_add(1).unwrap(); - if size < string_length { - return Ok((false, string_length)); - } - - // Store the UTF-16 string. - let size2 = Size::from_bytes(2); - let this = self.eval_context_mut(); - let mut alloc = this - .get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? - .unwrap(); // not a ZST, so we will get a result - for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let offset = u64::try_from(offset).unwrap(); - alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?; - } - Ok((true, string_length)) + self.eval_context_mut().write_wide_str(&u16_vec, ptr, size) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 70798f98174..d755e5f10ba 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -26,8 +26,12 @@ fn emulate_foreign_item_by_name( "pthread_set_name_np" => { let [thread, name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let res = - this.pthread_setname_np(this.read_scalar(thread)?, this.read_scalar(name)?)?; + let max_len = usize::MAX; // freebsd does not seem to have a limit. + let res = this.pthread_setname_np( + this.read_scalar(thread)?, + this.read_scalar(name)?, + max_len, + )?; this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 0610f65db11..b152082b4de 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -621,7 +621,7 @@ fn open(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { return Ok(-1); } - let fd = options.open(&path).map(|file| { + let fd = options.open(path).map(|file| { let fh = &mut this.machine.file_handler; fh.insert_fd(Box::new(FileHandle { file, writable })) }); @@ -1862,7 +1862,7 @@ fn mkstemp(&mut self, template_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx let possibly_unique = std::env::temp_dir().join::(p.into()); - let file = fopts.open(&possibly_unique); + let file = fopts.open(possibly_unique); match file { Ok(f) => { diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 5d000f9d121..2b53152688b 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -68,8 +68,22 @@ fn emulate_foreign_item_by_name( "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let res = - this.pthread_setname_np(this.read_scalar(thread)?, this.read_scalar(name)?)?; + let max_len = 16; + let res = this.pthread_setname_np( + this.read_scalar(thread)?, + this.read_scalar(name)?, + max_len, + )?; + this.write_scalar(res, dest)?; + } + "pthread_getname_np" => { + let [thread, name, len] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let res = this.pthread_getname_np( + this.read_scalar(thread)?, + this.read_scalar(name)?, + this.read_scalar(len)?, + )?; this.write_scalar(res, dest)?; } @@ -126,7 +140,7 @@ fn emulate_foreign_item_by_name( futex(this, &args[1..], dest)?; } id => { - this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; + this.handle_unsupported(format!("can't execute syscall with ID {id}"))?; return Ok(EmulateByNameResult::AlreadyJumped); } } diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 38d791fba98..371f56ca355 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -176,7 +176,22 @@ fn emulate_foreign_item_by_name( "pthread_setname_np" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let thread = this.pthread_self()?; - this.pthread_setname_np(thread, this.read_scalar(name)?)?; + let max_len = this.eval_libc("MAXTHREADNAMESIZE")?.to_machine_usize(this)?; + this.pthread_setname_np( + thread, + this.read_scalar(name)?, + max_len.try_into().unwrap(), + )?; + } + "pthread_getname_np" => { + let [thread, name, len] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let res = this.pthread_getname_np( + this.read_scalar(thread)?, + this.read_scalar(name)?, + this.read_scalar(len)?, + )?; + this.write_scalar(res, dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 59474d8d10a..b43682710bb 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -67,10 +67,13 @@ fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { Ok(Scalar::from_machine_usize(thread_id.into(), this)) } + /// Set the name of the current thread. `max_name_len` is the maximal length of the name + /// including the null terminator. fn pthread_setname_np( &mut self, thread: Scalar, name: Scalar, + max_name_len: usize, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); @@ -78,11 +81,35 @@ fn pthread_setname_np( let name = name.to_pointer(this)?; let name = this.read_c_str(name)?.to_owned(); + + // Comparing with `>=` to account for null terminator. + if name.len() >= max_name_len { + return this.eval_libc("ERANGE"); + } + this.set_thread_name(thread, name); Ok(Scalar::from_u32(0)) } + fn pthread_getname_np( + &mut self, + thread: Scalar, + name_out: Scalar, + len: Scalar, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let thread = ThreadId::try_from(thread.to_machine_usize(this)?).unwrap(); + let name_out = name_out.to_pointer(this)?; + let len = len.to_machine_usize(this)?; + + let name = this.get_thread_name(thread).to_owned(); + let (success, _written) = this.write_c_str(&name, name_out, len)?; + + if success { Ok(Scalar::from_u32(0)) } else { this.eval_libc("ERANGE") } + } + fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 184ba997fc8..2a34a3a47bb 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -418,13 +418,6 @@ fn emulate_foreign_item_by_name( // Indicate an error. this.write_null(dest)?; } - "GetFileInformationByHandleEx" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_hFile, _FileInformationClass, _lpFileInformation, _dwBufferSize] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - // Just make it fail. - this.write_null(dest)?; - } "GetFileType" if this.frame_in_std() => { #[allow(non_snake_case)] let [_hFile] = diff --git a/src/tools/miri/src/stacked_borrows/diagnostics.rs b/src/tools/miri/src/stacked_borrows/diagnostics.rs index 2cc7a88704e..d3843b03034 100644 --- a/src/tools/miri/src/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/stacked_borrows/diagnostics.rs @@ -86,12 +86,12 @@ fn generate_diagnostic(&self) -> (String, SpanData) { impl fmt::Display for InvalidationCause { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - InvalidationCause::Access(kind) => write!(f, "{}", kind), + InvalidationCause::Access(kind) => write!(f, "{kind}"), InvalidationCause::Retag(perm, kind) => if *kind == RetagCause::FnEntry { - write!(f, "{:?} FnEntry retag", perm) + write!(f, "{perm:?} FnEntry retag") } else { - write!(f, "{:?} retag", perm) + write!(f, "{perm:?} retag") }, } } @@ -339,7 +339,7 @@ pub fn get_logs_relevant_to( // this allocation. if self.history.base.0.tag() == tag { Some(( - format!("{:?} was created here, as the base tag for {:?}", tag, self.history.id), + format!("{tag:?} was created here, as the base tag for {:?}", self.history.id), self.history.base.1.data() )) } else { @@ -381,7 +381,7 @@ pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> self.offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(stack, op.orig_tag)), + format!("{action}{}", error_cause(stack, op.orig_tag)), Some(operation_summary(&op.cause.summary(), self.history.id, op.range)), op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)), ) @@ -401,7 +401,7 @@ pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> { offset = self.offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(stack, op.tag)), + format!("{action}{}", error_cause(stack, op.tag)), Some(operation_summary("an access", self.history.id, op.range)), op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), ) diff --git a/src/tools/miri/src/stacked_borrows/mod.rs b/src/tools/miri/src/stacked_borrows/mod.rs index 959e351d1a1..cc27b71eb56 100644 --- a/src/tools/miri/src/stacked_borrows/mod.rs +++ b/src/tools/miri/src/stacked_borrows/mod.rs @@ -1153,7 +1153,10 @@ fn print_stacks(&mut self, alloc_id: AllocId) -> InterpResult<'tcx> { let alloc_extra = this.get_alloc_extra(alloc_id)?; let stacks = alloc_extra.stacked_borrows.as_ref().unwrap().borrow(); for (range, stack) in stacks.stacks.iter_all() { - print!("{:?}: [", range); + print!("{range:?}: ["); + if let Some(bottom) = stack.unknown_bottom() { + print!(" unknown-bottom(..{bottom:?})"); + } for i in 0..stack.len() { let item = stack.get(i).unwrap(); print!(" {:?}{:?}", item.perm(), item.tag()); diff --git a/src/tools/miri/tests/pass-dep/shims/pthreads.rs b/src/tools/miri/tests/pass-dep/shims/pthreads.rs index d062eda7e90..bbddca74754 100644 --- a/src/tools/miri/tests/pass-dep/shims/pthreads.rs +++ b/src/tools/miri/tests/pass-dep/shims/pthreads.rs @@ -1,10 +1,14 @@ //@ignore-target-windows: No libc on Windows +#![feature(cstr_from_bytes_until_nul)] +use std::ffi::CStr; +use std::thread; fn main() { test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); + test_named_thread_truncation(); #[cfg(any(target_os = "linux"))] test_mutex_libc_static_initializer_recursive(); @@ -125,3 +129,24 @@ fn test_rwlock_libc_static_initializer() { assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); } } + +fn test_named_thread_truncation() { + let long_name = std::iter::once("test_named_thread_truncation") + .chain(std::iter::repeat(" yada").take(100)) + .collect::(); + + let result = thread::Builder::new().name(long_name.clone()).spawn(move || { + // Rust remembers the full thread name itself. + assert_eq!(thread::current().name(), Some(long_name.as_str())); + + // But the system is limited -- make sure we successfully set a truncation. + let mut buf = vec![0u8; long_name.len() + 1]; + unsafe { + libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); + } + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert!(cstr.to_bytes().len() >= 15); // POSIX seems to promise at least 15 chars + assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); + }); + result.unwrap().join().unwrap(); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs index 8d96a2e1ca9..3ca937ae13d 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] use std::{ alloc::{self, Layout}, mem::ManuallyDrop, @@ -5,25 +7,40 @@ extern "Rust" { fn miri_get_alloc_id(ptr: *const u8) -> u64; - fn miri_print_stacks(alloc_id: u64); + fn miri_print_borrow_stacks(alloc_id: u64); +} + +fn get_alloc_id(ptr: *const u8) -> u64 { + unsafe { miri_get_alloc_id(ptr) } +} + +fn print_borrow_stacks(alloc_id: u64) { + unsafe { miri_print_borrow_stacks(alloc_id) } } fn main() { let ptr = unsafe { alloc::alloc(Layout::new::()) }; - let alloc_id = unsafe { miri_get_alloc_id(ptr) }; - unsafe { miri_print_stacks(alloc_id) }; + let alloc_id = get_alloc_id(ptr); + print_borrow_stacks(alloc_id); assert!(!ptr.is_null()); - unsafe { miri_print_stacks(alloc_id) }; + print_borrow_stacks(alloc_id); unsafe { *ptr = 42 }; - unsafe { miri_print_stacks(alloc_id) }; + print_borrow_stacks(alloc_id); let _b = unsafe { ManuallyDrop::new(Box::from_raw(ptr)) }; - unsafe { miri_print_stacks(alloc_id) }; + print_borrow_stacks(alloc_id); let _ptr = unsafe { &*ptr }; - unsafe { miri_print_stacks(alloc_id) }; + print_borrow_stacks(alloc_id); + + // Create an unknown bottom, and print it + let ptr = ptr as usize as *mut u8; + unsafe { + *ptr = 5; + } + print_borrow_stacks(alloc_id); unsafe { alloc::dealloc(ptr, Layout::new::()) }; } diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout index 660ee71e6f5..83873307820 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout +++ b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout @@ -3,3 +3,4 @@ 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite Unique Unique Unique Unique Unique ] 0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] +0..1: [ unknown-bottom(..) ]