From c1875bfc24dbb88b1cd014cbb94099f708b5242b Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Wed, 4 Dec 2024 15:10:05 +0100 Subject: [PATCH 01/25] add test to demonstrate the effect of #4008 --- .../subtree_traversal_skipping_diagnostics.rs | 29 +++++++++++++++++ ...tree_traversal_skipping_diagnostics.stderr | 31 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs new file mode 100644 index 0000000000000..6514334b09df6 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs @@ -0,0 +1,29 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 + +// Shows the effect of the optimization of #4008. +// The diagnostics change, but not the error itself. + +// When this method is called, the tree will be a single line and look like this, +// with other_ptr being the root at the top +// other_ptr = root : Active +// intermediary : Frozen // an intermediary node +// m : Reserved +fn write_to_mut(m: &mut u8, other_ptr: *const u8) { + unsafe { + std::hint::black_box(*other_ptr); + } + // In line 17 above, m should have become Reserved (protected) so that this write is impossible. + // However, that does not happen because the read above is not forwarded to the subtree below + // the Frozen intermediary node. This does not affect UB, however, because the Frozen that blocked + // the read already prevents any child writes. + *m = 42; //~ERROR: /write access through .* is forbidden/ +} + +fn main() { + let root = 42u8; + unsafe { + let intermediary = &root; + let data = &mut *(core::ptr::addr_of!(*intermediary) as *mut u8); + write_to_mut(data, core::ptr::addr_of!(root)); + } +} diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr new file mode 100644 index 0000000000000..4968047d872b7 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr @@ -0,0 +1,31 @@ +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC + | +LL | *m = 42; + | ^^^^^^^ write access through at ALLOC[0x0] is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag has state Reserved (conflicted) which forbids this child write access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC + | +LL | fn write_to_mut(m: &mut u8, other_ptr: *const u8) { + | ^ +help: the accessed tag later transitioned to Reserved (conflicted) due to a foreign read access at offsets [0x0..0x1] + --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC + | +LL | std::hint::black_box(*other_ptr); + | ^^^^^^^^^^ + = help: this transition corresponds to a temporary loss of write permissions until function exit + = note: BACKTRACE (of the first span): + = note: inside `write_to_mut` at tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC +note: inside `main` + --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC + | +LL | write_to_mut(data, core::ptr::addr_of!(root)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From b984eaa5632beb966a13120a34247c186220aa3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Dec 2024 08:49:33 +0100 Subject: [PATCH 02/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 57d0b27dfd3b7..50710f55266e2 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -728f2daab42ba8f1b3d5caab62495798d1eabfa1 +1b3fb316751227d30b1523ed0e3f00d83956d4d0 From 4917fe5d4803157cb9a0e47da057c73ec78b089d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 9 Dec 2024 13:25:08 +0100 Subject: [PATCH 03/25] Enable `[bot-pull-requests]` triagebot feature --- src/tools/miri/triagebot.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index 2d93777f61d3d..3192882dff6d3 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -29,3 +29,6 @@ review_labels = ["S-waiting-on-review"] remove_labels = ["S-waiting-on-author"] # Those labels are added when PR author requests a review from an assignee add_labels = ["S-waiting-on-review"] + +# Automatically close and reopen PRs made by bots to run CI on them +[bot-pull-requests] From 0f920dbaf17584923f187d7727b7515f321216f7 Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Wed, 4 Dec 2024 14:42:53 +0100 Subject: [PATCH 04/25] TB: optimize accesses on large trees by ignoring subtrees if the access would mostly be a NOP --- .../src/borrow_tracker/tree_borrows/perms.rs | 4 +++ .../src/borrow_tracker/tree_borrows/tree.rs | 25 ++++++++++++++++++- ...tree_traversal_skipping_diagnostics.stderr | 12 ++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 6e157d3fcd34e..5d7c3d8c219f9 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -237,6 +237,10 @@ impl Permission { pub fn is_active(&self) -> bool { self.inner == Active } + /// Check if `self` is the never-allow-writes-again state of a pointer (is `Frozen`). + pub fn is_frozen(&self) -> bool { + self.inner == Frozen + } /// Default initial permission of the root of a new tree at inbounds positions. /// Must *only* be used for the root, this is not in general an "initial" permission! diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 6d4ec36f7b696..3e7d260622543 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -153,8 +153,31 @@ impl LocationState { ) -> ContinueTraversal { if rel_pos.is_foreign() { let happening_now = IdempotentForeignAccess::from_foreign(access_kind); - let new_access_noop = + let mut new_access_noop = self.idempotent_foreign_access.can_skip_foreign_access(happening_now); + if self.permission.is_disabled() { + // A foreign access to a `Disabled` tag will have almost no observable effect. + // It's a theorem that `Disabled` node have no protected initialized children, + // and so this foreign access will never trigger any protector. + // (Intuition: You're either protected initialized, and thus can't become Disabled + // or you're already Disabled protected, but not initialized, and then can't + // become initialized since that requires a child access, which Disabled blocks.) + // Further, the children will never be able to read or write again, since they + // have a `Disabled` parent. So this only affects diagnostics, such that the + // blocking write will still be identified directly, just at a different tag. + new_access_noop = true; + } + if self.permission.is_frozen() && access_kind == AccessKind::Read { + // A foreign read to a `Frozen` tag will have almost no observable effect. + // It's a theorem that `Frozen` nodes have no active children, so all children + // already survive foreign reads. Foreign reads in general have almost no + // effect, the only further thing they could do is make protected `Reserved` + // nodes become conflicted, i.e. make them reject child writes for the further + // duration of their protector. But such a child write is already rejected + // because this node is frozen. So this only affects diagnostics, but the + // blocking read will still be identified directly, just at a different tag. + new_access_noop = true; + } if new_access_noop { // Abort traversal if the new access is indeed guaranteed // to be noop. diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr index 4968047d872b7..d3ad2a39f2d2e 100644 --- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr @@ -5,18 +5,18 @@ LL | *m = 42; | ^^^^^^^ write access through at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: the accessed tag has state Reserved (conflicted) which forbids this child write access -help: the accessed tag was created here, in the initial state Reserved + = help: the accessed tag is a child of the conflicting tag + = help: the conflicting tag has state Frozen which forbids this child write access +help: the accessed tag was created here --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC | LL | fn write_to_mut(m: &mut u8, other_ptr: *const u8) { | ^ -help: the accessed tag later transitioned to Reserved (conflicted) due to a foreign read access at offsets [0x0..0x1] +help: the conflicting tag was created here, in the initial state Frozen --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC | -LL | std::hint::black_box(*other_ptr); - | ^^^^^^^^^^ - = help: this transition corresponds to a temporary loss of write permissions until function exit +LL | let intermediary = &root; + | ^^^^^ = note: BACKTRACE (of the first span): = note: inside `write_to_mut` at tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC note: inside `main` From 844635dfa33f8c5201fb5d48fa2c9630c50256c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Dec 2024 19:21:19 +0100 Subject: [PATCH 05/25] ./miri bench: set toolchain explicitly --- src/tools/miri/miri-script/src/commands.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 21029d0b5b3db..4b1cfffd4fe12 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -409,6 +409,7 @@ impl Command { OsString::new() }; let target_flag = &target_flag; + let toolchain = active_toolchain()?; // Run the requested benchmarks for bench in benches { let current_bench = path!(benches_dir / bench / "Cargo.toml"); @@ -416,7 +417,7 @@ impl Command { // That seems to make Windows CI happy. cmd!( sh, - "{program_name} {args...} 'cargo miri run '{target_flag}' --manifest-path \"'{current_bench}'\"'" + "{program_name} {args...} 'cargo +'{toolchain}' miri run '{target_flag}' --manifest-path \"'{current_bench}'\"'" ) .run()?; } From 579b680f5635e4e18cf05da02fc1193d159e47d5 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 2 Dec 2024 07:31:44 +0000 Subject: [PATCH 06/25] solarish stat following-up, supports for readdir. --- src/tools/miri/src/helpers.rs | 26 ++++++----- src/tools/miri/src/shims/unix/fs.rs | 45 +++++++++++++------ .../src/shims/unix/linux/foreign_items.rs | 2 +- .../src/shims/unix/solarish/foreign_items.rs | 6 +++ src/tools/miri/tests/pass/shims/fs.rs | 14 +++--- 5 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index b57ce4e070c38..7a85b4a4a6fd7 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -309,18 +309,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Project to the given *named* field (which must be a struct or union type). - fn project_field_named>( + fn try_project_field_named>( &self, base: &P, name: &str, - ) -> InterpResult<'tcx, P> { + ) -> InterpResult<'tcx, Option

> { let this = self.eval_context_ref(); let adt = base.layout().ty.ty_adt_def().unwrap(); for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { if field.name.as_str() == name { - return this.project_field(base, idx); + return interp_ok(Some(this.project_field(base, idx)?)); } } + interp_ok(None) + } + + /// Project to the given *named* field (which must be a struct or union type). + fn project_field_named>( + &self, + base: &P, + name: &str, + ) -> InterpResult<'tcx, P> { + if let Some(field) = self.try_project_field_named(base, name)? { + return interp_ok(field); + } bug!("No field named {} in type {}", name, base.layout().ty); } @@ -330,13 +342,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { base: &P, name: &str, ) -> bool { - let adt = base.layout().ty.ty_adt_def().unwrap(); - for field in adt.non_enum_variant().fields.iter() { - if field.name.as_str() == name { - return true; - } - } - false + self.try_project_field_named(base, name).unwrap().is_some() } /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index b41a4d2246ff0..5682fb659e7a1 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1048,10 +1048,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { + fn linux_solarish_readdir64( + &mut self, + dirent_type: &str, + dirp_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("linux", "readdir64"); + if !matches!(&*this.tcx.sess.target.os, "linux" | "solaris" | "illumos") { + panic!("`linux_solaris_readdir64` should not be called on {}", this.tcx.sess.target.os); + } let dirp = this.read_target_usize(dirp_op)?; @@ -1070,9 +1076,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some(Ok(dir_entry)) => { // Write the directory entry into a newly allocated buffer. // The name is written with write_bytes, while the rest of the - // dirent64 struct is written using write_int_fields. + // dirent64 (or dirent) struct is written using write_int_fields. // For reference: + // On Linux: // pub struct dirent64 { // pub d_ino: ino64_t, // pub d_off: off64_t, @@ -1080,19 +1087,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // pub d_type: c_uchar, // pub d_name: [c_char; 256], // } + // + // On Solaris: + // pub struct dirent { + // pub d_ino: ino64_t, + // pub d_off: off64_t, + // pub d_reclen: c_ushort, + // pub d_name: [c_char; 3], + // } let mut name = dir_entry.file_name(); // not a Path as there are no separators! name.push("\0"); // Add a NUL terminator let name_bytes = name.as_encoded_bytes(); let name_len = u64::try_from(name_bytes.len()).unwrap(); - let dirent64_layout = this.libc_ty_layout("dirent64"); - let d_name_offset = dirent64_layout.fields.offset(4 /* d_name */).bytes(); + let dirent_layout = this.libc_ty_layout(dirent_type); + let fields = &dirent_layout.fields; + let last_field = fields.count().strict_sub(1); + let d_name_offset = fields.offset(last_field).bytes(); let size = d_name_offset.strict_add(name_len); let entry = this.allocate_ptr( Size::from_bytes(size), - dirent64_layout.align.abi, + dirent_layout.align.abi, MiriMemoryKind::Runtime.into(), )?; let entry: Pointer = entry.into(); @@ -1105,17 +1122,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ino = 0u64; let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields_named( - &[ - ("d_ino", ino.into()), - ("d_off", 0), - ("d_reclen", size.into()), - ("d_type", file_type.into()), - ], - &this.ptr_to_mplace(entry, dirent64_layout), + &[("d_ino", ino.into()), ("d_off", 0), ("d_reclen", size.into())], + &this.ptr_to_mplace(entry, dirent_layout), )?; + if let Some(d_type) = this + .try_project_field_named(&this.ptr_to_mplace(entry, dirent_layout), "d_type")? + { + this.write_int(file_type, &d_type)?; + } + let name_ptr = entry.wrapping_offset(Size::from_bytes(d_name_offset), this); this.write_bytes_ptr(name_ptr, name_bytes.iter().copied())?; 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 bc3619090c087..6d0a2143fe36b 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "readdir64" => { let [dirp] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let result = this.linux_readdir64(dirp)?; + let result = this.linux_solarish_readdir64("dirent64", dirp)?; this.write_scalar(result, dest)?; } "sync_file_range" => { diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index e452917036840..faf280ad8815d 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -76,6 +76,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } + "readdir" => { + let [dirp] = + this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let result = this.linux_solarish_readdir64("dirent", dirp)?; + this.write_scalar(result, dest)?; + } // Miscellaneous "___errno" => { diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 3e514d95ee9c7..289c6aa2fcec9 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -27,11 +27,8 @@ fn main() { test_file_sync(); test_errors(); test_rename(); - // solarish needs to support readdir/readdir64 for these tests. - if cfg!(not(any(target_os = "solaris", target_os = "illumos"))) { - test_directory(); - test_canonicalize(); - } + test_directory(); + test_canonicalize(); test_from_raw_os_error(); #[cfg(unix)] test_pread_pwrite(); @@ -279,7 +276,12 @@ fn test_directory() { .collect::>() ); // Deleting the directory should fail, since it is not empty. - assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind()); + + // Solaris/Illumos `rmdir` call set errno to EEXIST if directory contains + // other entries than `.` and `..`. + // https://docs.oracle.com/cd/E86824_01/html/E54765/rmdir-2.html + let err = remove_dir(&dir_path).unwrap_err().kind(); + assert!(matches!(err, ErrorKind::AlreadyExists | ErrorKind::DirectoryNotEmpty)); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); From 0272b6cb32b5c8f16465b5d9b454cf08aee068e3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Dec 2024 07:24:45 +0100 Subject: [PATCH 07/25] ci TEST_BENCH: show output --- src/tools/miri/ci/ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 8e6e31bee4302..35d5cc7eeed01 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -73,7 +73,7 @@ function run_tests { fi if [ -n "${TEST_BENCH-}" ]; then # Check that the benchmarks build and run, but only once. - time HYPERFINE="hyperfine -w0 -r1" ./miri bench $TARGET_FLAG + time HYPERFINE="hyperfine -w0 -r1 --show-output" ./miri bench $TARGET_FLAG fi # Smoke-test `./miri run --dep`. ./miri run $TARGET_FLAG --dep tests/pass-dep/getrandom.rs From b7565cb1fe2cb99fd9421a9d8c6207f1bfad07e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Dec 2024 07:45:48 +0100 Subject: [PATCH 08/25] ./miri bench: add a flag to skip the install step --- src/tools/miri/ci/ci.sh | 4 ++-- src/tools/miri/miri-script/src/commands.rs | 11 +++++++---- src/tools/miri/miri-script/src/main.rs | 11 +++++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 35d5cc7eeed01..5da83a1623c60 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -18,7 +18,7 @@ export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--locked" -# Determine configuration for installed build (used by test-cargo-miri). +# Determine configuration for installed build (used by test-cargo-miri and `./miri bench`). echo "Installing release version of Miri" time ./miri install @@ -73,7 +73,7 @@ function run_tests { fi if [ -n "${TEST_BENCH-}" ]; then # Check that the benchmarks build and run, but only once. - time HYPERFINE="hyperfine -w0 -r1 --show-output" ./miri bench $TARGET_FLAG + time HYPERFINE="hyperfine -w0 -r1 --show-output" ./miri bench $TARGET_FLAG --no-install fi # Smoke-test `./miri run --dep`. ./miri run $TARGET_FLAG --dep tests/pass-dep/getrandom.rs diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 4b1cfffd4fe12..55005d86346f7 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -179,7 +179,8 @@ impl Command { Command::Doc { flags } => Self::doc(flags), Command::Fmt { flags } => Self::fmt(flags), Command::Clippy { flags } => Self::clippy(flags), - Command::Bench { target, benches } => Self::bench(target, benches), + Command::Bench { target, no_install, benches } => + Self::bench(target, no_install, benches), Command::Toolchain { flags } => Self::toolchain(flags), Command::RustcPull { commit } => Self::rustc_pull(commit.clone()), Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch), @@ -378,7 +379,7 @@ impl Command { Ok(()) } - fn bench(target: Option, benches: Vec) -> Result<()> { + fn bench(target: Option, no_install: bool, benches: Vec) -> Result<()> { // The hyperfine to use let hyperfine = env::var("HYPERFINE"); let hyperfine = hyperfine.as_deref().unwrap_or("hyperfine -w 1 -m 5 --shell=none"); @@ -386,8 +387,10 @@ impl Command { let Some((program_name, args)) = hyperfine.split_first() else { bail!("expected HYPERFINE environment variable to be non-empty"); }; - // Make sure we have an up-to-date Miri installed and selected the right toolchain. - Self::install(vec![])?; + if !no_install { + // Make sure we have an up-to-date Miri installed and selected the right toolchain. + Self::install(vec![])?; + } let sh = Shell::new()?; sh.change_dir(miri_dir()?); diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index a329f62790338..e1bf3c1862908 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -69,6 +69,8 @@ pub enum Command { /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. Bench { target: Option, + /// When `true`, skip the `./miri install` step. + no_install: bool, /// List of benchmarks to run. By default all benchmarks are run. benches: Vec, }, @@ -121,9 +123,11 @@ install`. Sets up the rpath such that the installed binary should work in any working directory. Note that the binaries are placed in the `miri` toolchain sysroot, to prevent conflicts with other toolchains. -./miri bench [--target ] : +./miri bench [--target ] [--no-install] : Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. can explicitly list the benchmarks to run; by default, all of them are run. +By default, this runs `./miri install` to ensure the latest local Miri is being benchmarked; +`--no-install` can be used to skip that step. ./miri toolchain : Update and activate the rustup toolchain 'miri' to the commit given in the @@ -218,16 +222,19 @@ fn main() -> Result<()> { Some("bench") => { let mut target = None; let mut benches = Vec::new(); + let mut no_install = false; loop { if let Some(val) = args.get_long_opt("target")? { target = Some(val); + } else if args.get_long_flag("no-install")? { + no_install = true; } else if let Some(flag) = args.get_other() { benches.push(flag); } else { break; } } - Command::Bench { target, benches } + Command::Bench { target, benches, no_install } } Some("toolchain") => Command::Toolchain { flags: args.remainder() }, Some("rustc-pull") => { From c7b8ee060d58f0382409a99a254b96f87f6dd581 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Dec 2024 10:37:23 +0100 Subject: [PATCH 09/25] bench-cargo-miri: bump lockfiles --- .../bench-cargo-miri/backtraces/Cargo.lock | 117 +++++++++++++----- .../miri/bench-cargo-miri/serde1/Cargo.lock | 45 ++++--- .../miri/bench-cargo-miri/serde2/Cargo.lock | 45 ++++--- .../miri/bench-cargo-miri/unicode/Cargo.lock | 6 +- 4 files changed, 138 insertions(+), 75 deletions(-) diff --git a/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock b/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock index 848864ea1f3be..86b5e9872e9de 100644 --- a/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock +++ b/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock @@ -1,35 +1,35 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.17.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -39,15 +39,6 @@ dependencies = [ "backtrace", ] -[[package]] -name = "cc" -version = "1.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -56,48 +47,106 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "gimli" -version = "0.26.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "object" -version = "0.28.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "shlex" -version = "1.3.0" +name = "windows_x86_64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/src/tools/miri/bench-cargo-miri/serde1/Cargo.lock b/src/tools/miri/bench-cargo-miri/serde1/Cargo.lock index 4875057613543..db64ee9a16dfd 100644 --- a/src/tools/miri/bench-cargo-miri/serde1/Cargo.lock +++ b/src/tools/miri/bench-cargo-miri/serde1/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "cargo-miri-test" @@ -12,48 +12,54 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -62,20 +68,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "syn" -version = "1.0.96" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -84,6 +91,6 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/src/tools/miri/bench-cargo-miri/serde2/Cargo.lock b/src/tools/miri/bench-cargo-miri/serde2/Cargo.lock index 4875057613543..db64ee9a16dfd 100644 --- a/src/tools/miri/bench-cargo-miri/serde2/Cargo.lock +++ b/src/tools/miri/bench-cargo-miri/serde2/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "cargo-miri-test" @@ -12,48 +12,54 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -62,20 +68,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "syn" -version = "1.0.96" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -84,6 +91,6 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/src/tools/miri/bench-cargo-miri/unicode/Cargo.lock b/src/tools/miri/bench-cargo-miri/unicode/Cargo.lock index 80d013b7d6d84..170c1529c22d8 100644 --- a/src/tools/miri/bench-cargo-miri/unicode/Cargo.lock +++ b/src/tools/miri/bench-cargo-miri/unicode/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "unicode" @@ -11,6 +11,6 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" From 6cbd1ebae38ce1a8d37401737a6236455e48d498 Mon Sep 17 00:00:00 2001 From: shamb0 Date: Tue, 3 Dec 2024 08:49:50 +0530 Subject: [PATCH 10/25] Improve timezone handling in 'localtime_r()' using 'allocate_bytes()' Signed-off-by: shamb0 --- src/tools/miri/src/shims/time.rs | 18 +- .../miri/tests/pass-dep/libc/libc-time.rs | 235 ++++++++++++++++-- 2 files changed, 233 insertions(+), 20 deletions(-) diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 6436823b0fdfe..11557d51c8e51 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -5,6 +5,8 @@ use std::time::{Duration, SystemTime}; use chrono::{DateTime, Datelike, Offset, Timelike, Utc}; use chrono_tz::Tz; +use rustc_abi::Align; +use rustc_ast::ast::Mutability; use crate::*; @@ -180,6 +182,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if !matches!(&*this.tcx.sess.target.os, "solaris" | "illumos") { // tm_zone represents the timezone value in the form of: +0730, +08, -0730 or -08. // This may not be consistent with libc::localtime_r's result. + let offset_in_seconds = dt.offset().fix().local_minus_utc(); let tm_gmtoff = offset_in_seconds; let mut tm_zone = String::new(); @@ -195,11 +198,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { write!(tm_zone, "{:02}", offset_min).unwrap(); } - // FIXME: String de-duplication is needed so that we only allocate this string only once - // even when there are multiple calls to this function. - let tm_zone_ptr = this - .alloc_os_str_as_c_str(&OsString::from(tm_zone), MiriMemoryKind::Machine.into())?; + // Add null terminator for C string compatibility. + tm_zone.push('\0'); + + // Deduplicate and allocate the string. + let tm_zone_ptr = this.allocate_bytes( + tm_zone.as_bytes(), + Align::ONE, + MiriMemoryKind::Machine.into(), + Mutability::Not, + )?; + // Write the timezone pointer and offset into the result structure. this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; this.write_int_fields_named(&[("tm_gmtoff", tm_gmtoff.into())], &result)?; } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index 84dbd8ad768f1..e53201e0bc5d1 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -5,7 +5,21 @@ use std::{env, mem, ptr}; fn main() { test_clocks(); test_posix_gettimeofday(); - test_localtime_r(); + test_localtime_r_gmt(); + test_localtime_r_pst(); + test_localtime_r_epoch(); + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] + test_localtime_r_multiple_calls_deduplication(); + // Architecture-specific tests. + #[cfg(target_pointer_width = "32")] + test_localtime_r_future_32b(); + #[cfg(target_pointer_width = "64")] + test_localtime_r_future_64b(); } /// Tests whether clock support exists at all @@ -46,14 +60,9 @@ fn test_posix_gettimeofday() { assert_eq!(is_error, -1); } -fn test_localtime_r() { - // Set timezone to GMT. - let key = "TZ"; - env::set_var(key, "GMT"); - - const TIME_SINCE_EPOCH: libc::time_t = 1712475836; - let custom_time_ptr = &TIME_SINCE_EPOCH; - let mut tm = libc::tm { +/// Helper function to create an empty tm struct. +fn create_empty_tm() -> libc::tm { + libc::tm { tm_sec: 0, tm_min: 0, tm_hour: 0, @@ -77,7 +86,17 @@ fn test_localtime_r() { target_os = "android" ))] tm_zone: std::ptr::null_mut::(), - }; + } +} + +/// Original GMT test +fn test_localtime_r_gmt() { + // Set timezone to GMT. + let key = "TZ"; + env::set_var(key, "GMT"); + const TIME_SINCE_EPOCH: libc::time_t = 1712475836; // 2024-04-07 07:43:56 GMT + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = create_empty_tm(); let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; assert_eq!(tm.tm_sec, 56); @@ -95,20 +114,204 @@ fn test_localtime_r() { target_os = "freebsd", target_os = "android" ))] - assert_eq!(tm.tm_gmtoff, 0); + { + assert_eq!(tm.tm_gmtoff, 0); + unsafe { + assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00"); + } + } + + // The returned value is the pointer passed in. + assert!(ptr::eq(res, &mut tm)); + + // Remove timezone setting. + env::remove_var(key); +} + +/// PST timezone test (testing different timezone handling). +fn test_localtime_r_pst() { + let key = "TZ"; + env::set_var(key, "PST8PDT"); + const TIME_SINCE_EPOCH: libc::time_t = 1712475836; // 2024-04-07 07:43:56 GMT + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = create_empty_tm(); + + let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; + + assert_eq!(tm.tm_sec, 56); + assert_eq!(tm.tm_min, 43); + assert_eq!(tm.tm_hour, 0); // 7 - 7 = 0 (PDT offset) + assert_eq!(tm.tm_mday, 7); + assert_eq!(tm.tm_mon, 3); + assert_eq!(tm.tm_year, 124); + assert_eq!(tm.tm_wday, 0); + assert_eq!(tm.tm_yday, 97); + assert_eq!(tm.tm_isdst, -1); // DST information unavailable + #[cfg(any( target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "android" ))] - unsafe { - assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") - }; + { + assert_eq!(tm.tm_gmtoff, -7 * 3600); // -7 hours in seconds + unsafe { + assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "-07"); + } + } - // The returned value is the pointer passed in. assert!(ptr::eq(res, &mut tm)); + env::remove_var(key); +} - // Remove timezone setting. +/// Unix epoch test (edge case testing). +fn test_localtime_r_epoch() { + let key = "TZ"; + env::set_var(key, "GMT"); + const TIME_SINCE_EPOCH: libc::time_t = 0; // 1970-01-01 00:00:00 + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = create_empty_tm(); + + let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; + + assert_eq!(tm.tm_sec, 0); + assert_eq!(tm.tm_min, 0); + assert_eq!(tm.tm_hour, 0); + assert_eq!(tm.tm_mday, 1); + assert_eq!(tm.tm_mon, 0); + assert_eq!(tm.tm_year, 70); + assert_eq!(tm.tm_wday, 4); // Thursday + assert_eq!(tm.tm_yday, 0); + assert_eq!(tm.tm_isdst, -1); + + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] + { + assert_eq!(tm.tm_gmtoff, 0); + unsafe { + assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00"); + } + } + + assert!(ptr::eq(res, &mut tm)); + env::remove_var(key); +} + +/// Future date test (testing large values). +#[cfg(target_pointer_width = "64")] +fn test_localtime_r_future_64b() { + let key = "TZ"; + env::set_var(key, "GMT"); + + // Using 2050-01-01 00:00:00 for 64-bit systems + // value that's safe for 64-bit time_t + const TIME_SINCE_EPOCH: libc::time_t = 2524608000; + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = create_empty_tm(); + + let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; + + assert_eq!(tm.tm_sec, 0); + assert_eq!(tm.tm_min, 0); + assert_eq!(tm.tm_hour, 0); + assert_eq!(tm.tm_mday, 1); + assert_eq!(tm.tm_mon, 0); + assert_eq!(tm.tm_year, 150); // 2050 - 1900 + assert_eq!(tm.tm_wday, 6); // Saturday + assert_eq!(tm.tm_yday, 0); + assert_eq!(tm.tm_isdst, -1); + + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] + { + assert_eq!(tm.tm_gmtoff, 0); + unsafe { + assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00"); + } + } + + assert!(ptr::eq(res, &mut tm)); + env::remove_var(key); +} + +/// Future date test (testing large values for 32b target). +#[cfg(target_pointer_width = "32")] +fn test_localtime_r_future_32b() { + let key = "TZ"; + env::set_var(key, "GMT"); + + // Using 2030-01-01 00:00:00 for 32-bit systems + // Safe value within i32 range + const TIME_SINCE_EPOCH: libc::time_t = 1893456000; + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = create_empty_tm(); + + let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; + + // Verify 2030-01-01 00:00:00 + assert_eq!(tm.tm_sec, 0); + assert_eq!(tm.tm_min, 0); + assert_eq!(tm.tm_hour, 0); + assert_eq!(tm.tm_mday, 1); + assert_eq!(tm.tm_mon, 0); + assert_eq!(tm.tm_year, 130); // 2030 - 1900 + assert_eq!(tm.tm_wday, 2); // Tuesday + assert_eq!(tm.tm_yday, 0); + assert_eq!(tm.tm_isdst, -1); + + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] + { + assert_eq!(tm.tm_gmtoff, 0); + unsafe { + assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00"); + } + } + + assert!(ptr::eq(res, &mut tm)); env::remove_var(key); } + +/// Tests the behavior of `localtime_r` with multiple calls to ensure deduplication of `tm_zone` pointers. +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "android"))] +fn test_localtime_r_multiple_calls_deduplication() { + let key = "TZ"; + env::set_var(key, "PST8PDT"); + + const TIME_SINCE_EPOCH_BASE: libc::time_t = 1712475836; // Base timestamp: 2024-04-07 07:43:56 GMT + const NUM_CALLS: usize = 50; + + let mut unique_pointers = std::collections::HashSet::new(); + + for i in 0..NUM_CALLS { + let timestamp = TIME_SINCE_EPOCH_BASE + (i as libc::time_t * 3600); // Increment by 1 hour for each call + let mut tm: libc::tm = create_empty_tm(); + let tm_ptr = unsafe { libc::localtime_r(×tamp, &mut tm) }; + + assert!(!tm_ptr.is_null(), "localtime_r failed for timestamp {timestamp}"); + + unique_pointers.insert(tm.tm_zone); + } + + let unique_count = unique_pointers.len(); + + assert!( + unique_count >= 2 && unique_count <= (NUM_CALLS - 1), + "Unexpected number of unique tm_zone pointers: {} (expected between 2 and {})", + unique_count, + NUM_CALLS - 1 + ); +} From cc797a2b741be734289ba857e99dc72be908d92d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Dec 2024 12:24:25 +0100 Subject: [PATCH 11/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 50710f55266e2..03ad4a74a2c56 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1b3fb316751227d30b1523ed0e3f00d83956d4d0 +903d2976fdb6ceeb65526b7555d8d1e6f8c02134 From 202098e049bfd0e505ad7f698ed281e58bcdfa58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Dec 2024 12:27:01 +0100 Subject: [PATCH 12/25] fix use of this.allocate_bytes --- src/tools/miri/src/shims/time.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 11557d51c8e51..72d98bc1c4872 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -5,8 +5,6 @@ use std::time::{Duration, SystemTime}; use chrono::{DateTime, Datelike, Offset, Timelike, Utc}; use chrono_tz::Tz; -use rustc_abi::Align; -use rustc_ast::ast::Mutability; use crate::*; @@ -202,12 +200,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { tm_zone.push('\0'); // Deduplicate and allocate the string. - let tm_zone_ptr = this.allocate_bytes( - tm_zone.as_bytes(), - Align::ONE, - MiriMemoryKind::Machine.into(), - Mutability::Not, - )?; + let tm_zone_ptr = this.allocate_bytes_dedup(tm_zone.as_bytes())?; // Write the timezone pointer and offset into the result structure. this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; From 70628f8b8d58e720ca91ec558e9d80797bfa6387 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 13 Dec 2024 05:04:35 +0000 Subject: [PATCH 13/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 03ad4a74a2c56..ff62667f9b8f0 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -903d2976fdb6ceeb65526b7555d8d1e6f8c02134 +f4f0fafd0c7849e162eddbc69fa5fe82dbec28c7 From c1657ca1b0bd3849d1ef779e368715462eb33122 Mon Sep 17 00:00:00 2001 From: Konstantin Andrikopoulos Date: Sat, 16 Nov 2024 15:27:31 +0100 Subject: [PATCH 14/25] experiment with using clap --- src/tools/miri/miri-script/Cargo.lock | 122 ++++++++++++- src/tools/miri/miri-script/Cargo.toml | 1 + src/tools/miri/miri-script/src/args.rs | 135 -------------- src/tools/miri/miri-script/src/main.rs | 241 ++++++++----------------- 4 files changed, 194 insertions(+), 305 deletions(-) delete mode 100644 src/tools/miri/miri-script/src/args.rs diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 0c0fe477cddc7..0208327a8ddcf 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -2,6 +2,55 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + [[package]] name = "anyhow" version = "1.0.80" @@ -20,6 +69,52 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "directories" version = "5.0.1" @@ -80,6 +175,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "home" version = "0.5.9" @@ -89,6 +190,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.11.0" @@ -137,6 +244,7 @@ name = "miri-script" version = "0.1.0" dependencies = [ "anyhow", + "clap", "directories", "dunce", "itertools", @@ -278,6 +386,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.50" @@ -328,6 +442,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "walkdir" version = "2.4.0" @@ -362,7 +482,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 5b31d5a6ff97b..0ab49bbacfc70 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -25,3 +25,4 @@ dunce = "1.0.4" directories = "5" serde_json = "1" tempfile = "3.13.0" +clap = { version = "4.5.21", features = ["derive"] } diff --git a/src/tools/miri/miri-script/src/args.rs b/src/tools/miri/miri-script/src/args.rs deleted file mode 100644 index 55d9de4233d9b..0000000000000 --- a/src/tools/miri/miri-script/src/args.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::{env, iter}; - -use anyhow::{Result, bail}; - -pub struct Args { - args: iter::Peekable, - /// Set to `true` once we saw a `--`. - terminated: bool, -} - -impl Args { - pub fn new() -> Self { - let mut args = Args { args: env::args().peekable(), terminated: false }; - args.args.next().unwrap(); // skip program name - args - } - - /// Get the next argument without any interpretation. - pub fn next_raw(&mut self) -> Option { - self.args.next() - } - - /// Consume a `-$f` flag if present. - pub fn get_short_flag(&mut self, flag: char) -> Result { - if self.terminated { - return Ok(false); - } - if let Some(next) = self.args.peek() { - if let Some(next) = next.strip_prefix("-") { - if let Some(next) = next.strip_prefix(flag) { - if next.is_empty() { - self.args.next().unwrap(); // consume this argument - return Ok(true); - } else { - bail!("`-{flag}` followed by value"); - } - } - } - } - Ok(false) - } - - /// Consume a `--$name` flag if present. - pub fn get_long_flag(&mut self, name: &str) -> Result { - if self.terminated { - return Ok(false); - } - if let Some(next) = self.args.peek() { - if let Some(next) = next.strip_prefix("--") { - if next == name { - self.args.next().unwrap(); // consume this argument - return Ok(true); - } - } - } - Ok(false) - } - - /// Consume a `--$name val` or `--$name=val` option if present. - pub fn get_long_opt(&mut self, name: &str) -> Result> { - assert!(!name.is_empty()); - if self.terminated { - return Ok(None); - } - let Some(next) = self.args.peek() else { return Ok(None) }; - let Some(next) = next.strip_prefix("--") else { return Ok(None) }; - let Some(next) = next.strip_prefix(name) else { return Ok(None) }; - // Starts with `--flag`. - Ok(if let Some(val) = next.strip_prefix("=") { - // `--flag=val` form - let val = val.into(); - self.args.next().unwrap(); // consume this argument - Some(val) - } else if next.is_empty() { - // `--flag val` form - self.args.next().unwrap(); // consume this argument - let Some(val) = self.args.next() else { bail!("`--{name}` not followed by value") }; - Some(val) - } else { - // Some unrelated flag, like `--flag-more` or so. - None - }) - } - - /// Consume a `--$name=val` or `--$name` option if present; the latter - /// produces a default value. (`--$name val` is *not* accepted for this form - /// of argument, it understands `val` already as the next argument!) - pub fn get_long_opt_with_default( - &mut self, - name: &str, - default: &str, - ) -> Result> { - assert!(!name.is_empty()); - if self.terminated { - return Ok(None); - } - let Some(next) = self.args.peek() else { return Ok(None) }; - let Some(next) = next.strip_prefix("--") else { return Ok(None) }; - let Some(next) = next.strip_prefix(name) else { return Ok(None) }; - // Starts with `--flag`. - Ok(if let Some(val) = next.strip_prefix("=") { - // `--flag=val` form - let val = val.into(); - self.args.next().unwrap(); // consume this argument - Some(val) - } else if next.is_empty() { - // `--flag` form - self.args.next().unwrap(); // consume this argument - Some(default.into()) - } else { - // Some unrelated flag, like `--flag-more` or so. - None - }) - } - - /// Returns the next free argument or uninterpreted flag, or `None` if there are no more - /// arguments left. `--` is returned as well, but it is interpreted in the sense that no more - /// flags will be parsed after this. - pub fn get_other(&mut self) -> Option { - if self.terminated { - return self.args.next(); - } - let next = self.args.next()?; - if next == "--" { - self.terminated = true; // don't parse any more flags - // This is where our parser is special, we do yield the `--`. - } - Some(next) - } - - /// Return the rest of the aguments entirely unparsed. - pub fn remainder(self) -> Vec { - self.args.collect() - } -} diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index e1bf3c1862908..f0f4778f83a29 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -1,15 +1,33 @@ #![allow(clippy::needless_question_mark)] -mod args; mod commands; mod coverage; mod util; use std::ops::Range; -use anyhow::{Context, Result, anyhow, bail}; +use anyhow::{Context, Result, anyhow}; +use clap::{Parser, Subcommand}; + +/// Parses a seed range +/// +/// This function is used for the `--many-seeds` flag. It expects the range in the form +/// `..`. `` is inclusive, `` is exclusive. `` can be omitted, +/// in which case it is assumed to be `0`. +fn parse_range(val: &str) -> anyhow::Result> { + let (from, to) = val + .split_once("..") + .ok_or_else(|| anyhow!("invalid format for `--many-seeds`: expected `from..to`"))?; + let from: u32 = if from.is_empty() { + 0 + } else { + from.parse().context("invalid `from` in `--many-seeds=from..to")? + }; + let to: u32 = to.parse().context("invalid `to` in `--many-seeds=from..to")?; + Ok(from..to) +} -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Subcommand)] pub enum Command { /// Installs the miri driver and cargo-miri. /// Sets up the rpath such that the installed binary should work in any @@ -17,57 +35,74 @@ pub enum Command { /// sysroot, to prevent conflicts with other toolchains. Install { /// Flags that are passed through to `cargo install`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Just build miri. Build { /// Flags that are passed through to `cargo build`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Just check miri. Check { /// Flags that are passed through to `cargo check`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Build miri, set up a sysroot and then run the test suite. Test { + #[arg(long)] bless: bool, /// The cross-interpretation target. /// If none then the host is the target. + #[arg(long)] target: Option, /// Produce coverage report if set. + #[arg(long)] coverage: bool, /// Flags that are passed through to the test harness. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Build miri, set up a sysroot and then run the driver with the given . /// (Also respects MIRIFLAGS environment variable.) Run { + #[arg(long)] dep: bool, + #[arg(long, short)] verbose: bool, + #[arg(long, value_parser = parse_range)] many_seeds: Option>, + #[arg(long)] target: Option, + #[arg(long)] edition: Option, /// Flags that are passed through to `miri`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Build documentation Doc { /// Flags that are passed through to `cargo doc`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Format all sources and tests. Fmt { /// Flags that are passed through to `rustfmt`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Runs clippy on all sources. Clippy { /// Flags that are passed through to `cargo clippy`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. Bench { + #[arg(long)] target: Option, /// When `true`, skip the `./miri install` step. no_install: bool, @@ -89,176 +124,44 @@ pub enum Command { RustcPush { github_user: String, branch: String }, } -const HELP: &str = r#" COMMANDS - -./miri build : -Just build miri. are passed to `cargo build`. - -./miri check : -Just check miri. are passed to `cargo check`. - -./miri test [--bless] [--target ] : -Build miri, set up a sysroot and then run the test suite. - are passed to the test harness. - -./miri run [--dep] [-v|--verbose] [--many-seeds|--many-seeds=..to|--many-seeds=from..to] : -Build miri, set up a sysroot and then run the driver with the given . -(Also respects MIRIFLAGS environment variable.) -If `--many-seeds` is present, Miri is run many times in parallel with different seeds. -The range defaults to `0..64`. - -./miri fmt : -Format all sources and tests. are passed to `rustfmt`. - -./miri clippy : -Runs clippy on all sources. are passed to `cargo clippy`. - -./miri cargo : -Runs just `cargo ` with the Miri-specific environment variables. -Mainly meant to be invoked by rust-analyzer. - -./miri install : -Installs the miri driver and cargo-miri. are passed to `cargo -install`. Sets up the rpath such that the installed binary should work in any -working directory. Note that the binaries are placed in the `miri` toolchain -sysroot, to prevent conflicts with other toolchains. - -./miri bench [--target ] [--no-install] : -Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. - can explicitly list the benchmarks to run; by default, all of them are run. -By default, this runs `./miri install` to ensure the latest local Miri is being benchmarked; -`--no-install` can be used to skip that step. - -./miri toolchain : -Update and activate the rustup toolchain 'miri' to the commit given in the -`rust-version` file. -`rustup-toolchain-install-master` must be installed for this to work. Any extra -flags are passed to `rustup-toolchain-install-master`. - -./miri rustc-pull : -Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest -rustc commit. The fetched commit is stored in the `rust-version` file, so the -next `./miri toolchain` will install the rustc that just got pulled. - -./miri rustc-push []: -Push Miri changes back to the rustc repo. This will pull a copy of the rustc -history into the Miri repo, unless you set the RUSTC_GIT env var to an existing -clone of the rustc repo. The branch defaults to `miri-sync`. - - ENVIRONMENT VARIABLES +impl Command { + fn add_remainder(&mut self, remainder: Vec) -> Result<()> { + if remainder.is_empty() { + return Ok(()); + } -MIRI_SYSROOT: -If already set, the "sysroot setup" step is skipped. + match self { + Self::Install { flags } + | Self::Build { flags } + | Self::Check { flags } + | Self::Doc { flags } + | Self::Fmt { flags } + | Self::Toolchain { flags } + | Self::Clippy { flags } + | Self::Run { flags, .. } + | Self::Test { flags, .. } => { + flags.extend(remainder); + Ok(()) + } + Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } => + Err(anyhow::Error::msg("unexpected \"--\" found in arguments")), + } + } +} -CARGO_EXTRA_FLAGS: -Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)"#; +#[derive(Parser)] +pub struct Cli { + #[command(subcommand)] + pub command: Command, +} fn main() -> Result<()> { - // We are hand-rolling our own argument parser, since `clap` can't express what we need - // (https://github.com/clap-rs/clap/issues/5055). - let mut args = args::Args::new(); - let command = match args.next_raw().as_deref() { - Some("build") => Command::Build { flags: args.remainder() }, - Some("check") => Command::Check { flags: args.remainder() }, - Some("doc") => Command::Doc { flags: args.remainder() }, - Some("test") => { - let mut target = None; - let mut bless = false; - let mut flags = Vec::new(); - let mut coverage = false; - loop { - if args.get_long_flag("bless")? { - bless = true; - } else if args.get_long_flag("coverage")? { - coverage = true; - } else if let Some(val) = args.get_long_opt("target")? { - target = Some(val); - } else if let Some(flag) = args.get_other() { - flags.push(flag); - } else { - break; - } - } - Command::Test { bless, flags, target, coverage } - } - Some("run") => { - let mut dep = false; - let mut verbose = false; - let mut many_seeds = None; - let mut target = None; - let mut edition = None; - let mut flags = Vec::new(); - loop { - if args.get_long_flag("dep")? { - dep = true; - } else if args.get_long_flag("verbose")? || args.get_short_flag('v')? { - verbose = true; - } else if let Some(val) = args.get_long_opt_with_default("many-seeds", "0..64")? { - let (from, to) = val.split_once("..").ok_or_else(|| { - anyhow!("invalid format for `--many-seeds`: expected `from..to`") - })?; - let from: u32 = if from.is_empty() { - 0 - } else { - from.parse().context("invalid `from` in `--many-seeds=from..to")? - }; - let to: u32 = to.parse().context("invalid `to` in `--many-seeds=from..to")?; - many_seeds = Some(from..to); - } else if let Some(val) = args.get_long_opt("target")? { - target = Some(val); - } else if let Some(val) = args.get_long_opt("edition")? { - edition = Some(val); - } else if let Some(flag) = args.get_other() { - flags.push(flag); - } else { - break; - } - } - Command::Run { dep, verbose, many_seeds, target, edition, flags } - } - Some("fmt") => Command::Fmt { flags: args.remainder() }, - Some("clippy") => Command::Clippy { flags: args.remainder() }, - Some("install") => Command::Install { flags: args.remainder() }, - Some("bench") => { - let mut target = None; - let mut benches = Vec::new(); - let mut no_install = false; - loop { - if let Some(val) = args.get_long_opt("target")? { - target = Some(val); - } else if args.get_long_flag("no-install")? { - no_install = true; - } else if let Some(flag) = args.get_other() { - benches.push(flag); - } else { - break; - } - } - Command::Bench { target, benches, no_install } - } - Some("toolchain") => Command::Toolchain { flags: args.remainder() }, - Some("rustc-pull") => { - let commit = args.next_raw(); - if args.next_raw().is_some() { - bail!("Too many arguments for `./miri rustc-pull`"); - } - Command::RustcPull { commit } - } - Some("rustc-push") => { - let github_user = args.next_raw().ok_or_else(|| { - anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER [BRANCH]`") - })?; - let branch = args.next_raw().unwrap_or_else(|| "miri-sync".into()); - if args.next_raw().is_some() { - bail!("Too many arguments for `./miri rustc-push GITHUB_USER BRANCH`"); - } - Command::RustcPush { github_user, branch } - } - _ => { - eprintln!("Unknown or missing command. Usage:\n\n{HELP}"); - std::process::exit(1); - } - }; + let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); + let remainder: Vec<_> = std::env::args().skip_while(|x| *x != "--").collect(); + + let args = Cli::parse_from(miri_args); + let mut command = args.command; + command.add_remainder(remainder)?; command.exec()?; Ok(()) } From d12597ff7b41d07c88593a4f99e917b1859e0596 Mon Sep 17 00:00:00 2001 From: Kostis Andrikopoulos Date: Fri, 13 Dec 2024 21:21:12 +0100 Subject: [PATCH 15/25] Update miri-script/src/main.rs Co-authored-by: Ralf Jung --- src/tools/miri/miri-script/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index f0f4778f83a29..1e816e7262d74 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -156,6 +156,8 @@ pub struct Cli { } fn main() -> Result<()> { + /// Split the arguments into the part before the `--` and the part after. + /// The `--` itself ends up in the second part. let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); let remainder: Vec<_> = std::env::args().skip_while(|x| *x != "--").collect(); From de5201fe1fbb04fc5ebc417ce4046647e56393a7 Mon Sep 17 00:00:00 2001 From: Konstantin Andrikopoulos Date: Fri, 13 Dec 2024 21:32:51 +0100 Subject: [PATCH 16/25] address comments --- src/tools/miri/miri-script/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 1e816e7262d74..ab0c4e1391175 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -6,7 +6,7 @@ mod util; use std::ops::Range; -use anyhow::{Context, Result, anyhow}; +use anyhow::{Context, Result, anyhow, bail}; use clap::{Parser, Subcommand}; /// Parses a seed range @@ -144,7 +144,7 @@ impl Command { Ok(()) } Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } => - Err(anyhow::Error::msg("unexpected \"--\" found in arguments")), + bail!("unexpected \"--\" found in arguments"), } } } @@ -156,8 +156,8 @@ pub struct Cli { } fn main() -> Result<()> { - /// Split the arguments into the part before the `--` and the part after. - /// The `--` itself ends up in the second part. + // Split the arguments into the part before the `--` and the part after. + // The `--` itself ends up in the second part. let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); let remainder: Vec<_> = std::env::args().skip_while(|x| *x != "--").collect(); From 7d40bb9b2faf3ae492a138e8912fbef74c21cf96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Dec 2024 09:59:44 +0100 Subject: [PATCH 17/25] fix 'rustc-push' and adjust help texts --- src/tools/miri/miri-script/src/main.rs | 92 +++++++++++++++++--------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index ab0c4e1391175..7592e56cfcfee 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -29,60 +29,74 @@ fn parse_range(val: &str) -> anyhow::Result> { #[derive(Clone, Debug, Subcommand)] pub enum Command { - /// Installs the miri driver and cargo-miri. + /// Installs the miri driver and cargo-miri to the sysroot of the active toolchain. + /// /// Sets up the rpath such that the installed binary should work in any - /// working directory. Note that the binaries are placed in the `miri` toolchain - /// sysroot, to prevent conflicts with other toolchains. + /// working directory. Install { /// Flags that are passed through to `cargo install`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Just build miri. + /// Build Miri. Build { /// Flags that are passed through to `cargo build`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Just check miri. + /// Check Miri. Check { /// Flags that are passed through to `cargo check`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Build miri, set up a sysroot and then run the test suite. + /// Check Miri with Clippy. + Clippy { + /// Flags that are passed through to `cargo clippy`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + flags: Vec, + }, + /// Run the Miri test suite. Test { + /// Update stdout/stderr reference files. #[arg(long)] bless: bool, /// The cross-interpretation target. - /// If none then the host is the target. #[arg(long)] target: Option, - /// Produce coverage report if set. + /// Produce coverage report. #[arg(long)] coverage: bool, /// Flags that are passed through to the test harness. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Build miri, set up a sysroot and then run the driver with the given . - /// (Also respects MIRIFLAGS environment variable.) + /// Run the Miri driver. + /// + /// Also respects MIRIFLAGS environment variable. Run { + /// Build the program with the dependencies declared in `test_dependencies/Cargo.toml`. #[arg(long)] dep: bool, + /// Show build progress. #[arg(long, short)] verbose: bool, + /// Run the driver with the seeds in the given range (`..to` or `from..to`, default: `0..64`). #[arg(long, value_parser = parse_range)] many_seeds: Option>, + /// The cross-interpretation target. #[arg(long)] target: Option, + /// The Rust edition. #[arg(long)] edition: Option, /// Flags that are passed through to `miri`. + /// + /// The flags set in `MIRIFLAGS` are added in front of these flags. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Build documentation + /// Build documentation. Doc { /// Flags that are passed through to `cargo doc`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] @@ -94,34 +108,45 @@ pub enum Command { #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Runs clippy on all sources. - Clippy { - /// Flags that are passed through to `cargo clippy`. - #[arg(trailing_var_arg = true, allow_hyphen_values = true)] - flags: Vec, - }, - /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. + /// Runs the benchmarks from bench-cargo-miri in hyperfine. + /// + /// hyperfine needs to be installed. Bench { #[arg(long)] target: Option, /// When `true`, skip the `./miri install` step. + #[arg(long)] no_install: bool, - /// List of benchmarks to run. By default all benchmarks are run. + /// List of benchmarks to run (default: run all benchmarks). benches: Vec, }, - /// Update and activate the rustup toolchain 'miri' to the commit given in the - /// `rust-version` file. - /// `rustup-toolchain-install-master` must be installed for this to work. Any extra - /// flags are passed to `rustup-toolchain-install-master`. - Toolchain { flags: Vec }, - /// Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest - /// rustc commit. The fetched commit is stored in the `rust-version` file, so the - /// next `./miri toolchain` will install the rustc that just got pulled. - RustcPull { commit: Option }, - /// Push Miri changes back to the rustc repo. This will pull a copy of the rustc - /// history into the Miri repo, unless you set the RUSTC_GIT env var to an existing - /// clone of the rustc repo. - RustcPush { github_user: String, branch: String }, + /// Update and activate the rustup toolchain 'miri'. + /// + /// The `rust-version` file is used to determine the commit that will be intsalled. + /// `rustup-toolchain-install-master` must be installed for this to work. + Toolchain { + /// Flags that are passed through to `rustup-toolchain-install-master`. + flags: Vec, + }, + /// Pull and merge Miri changes from the rustc repo. + /// + /// The fetched commit is stored in the `rust-version` file, so the next `./miri toolchain` will + /// install the rustc that just got pulled. + RustcPull { + /// The commit to fetch (default: latest rustc commit). + commit: Option, + }, + /// Push Miri changes back to the rustc repo. + /// + /// This will pull a copy of the rustc history into the Miri repo, unless you set the RUSTC_GIT + /// env var to an existing clone of the rustc repo. + RustcPush { + /// The Github user that owns the rustc fork to which we should push. + github_user: String, + /// The branch to push to. + #[arg(default_value = "miri-sync")] + branch: String, + }, } impl Command { @@ -150,6 +175,9 @@ impl Command { } #[derive(Parser)] +#[command(after_help = "Environment variables: + MIRI_SYSROOT: If already set, the \"sysroot setup\" step is skipped + CARGO_EXTRA_FLAGS: Pass extra flags to all cargo invocations")] pub struct Cli { #[command(subcommand)] pub command: Command, From 8f497995ddecbe89efea7d88e8b381da24aac8ed Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 15 Dec 2024 05:00:34 +0000 Subject: [PATCH 18/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index ff62667f9b8f0..68131efa38751 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f4f0fafd0c7849e162eddbc69fa5fe82dbec28c7 +7caf35b2e5401d7740fdc567fdc388059208150b From b6120f98c5ad9f16d613d6fd55f546b186d40bae Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 18 Dec 2024 04:56:05 +0000 Subject: [PATCH 19/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 68131efa38751..bc92d07323fa3 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7caf35b2e5401d7740fdc567fdc388059208150b +52890e82153cd8716d97a96f47fb6ac99dec65be From 1f771300002f69b03807f26b47fc6ff1a68a9b14 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 29 Nov 2024 00:04:01 +0800 Subject: [PATCH 20/25] Implement blocking unnamed_socket --- src/tools/miri/src/concurrency/thread.rs | 2 + .../miri/src/shims/unix/unnamed_socket.rs | 237 ++++++++++++------ .../libc/socketpair_block_read_twice.rs | 47 ++++ .../libc/socketpair_block_read_twice.stderr | 41 +++ .../libc/socketpair_block_write_twice.rs | 49 ++++ .../libc/socketpair_block_write_twice.stderr | 41 +++ .../fail-dep/libc/socketpair_read_blocking.rs | 12 - .../libc/socketpair_read_blocking.stderr | 5 +- .../libc/socketpair_write_blocking.rs | 16 -- .../libc/socketpair_write_blocking.stderr | 5 +- .../tests/pass-dep/libc/libc-socketpair.rs | 50 ++++ 11 files changed, 391 insertions(+), 114 deletions(-) create mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs create mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr create mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs create mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr delete mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs delete mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 59e2fdd428504..730c27d0160bb 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -159,6 +159,8 @@ pub enum BlockReason { Epoll, /// Blocked on eventfd. Eventfd, + /// Blocked on unnamed_socket. + UnnamedSocket, } /// The state of a thread. diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 40a76ea7439a2..86ebe95762a6c 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -36,6 +36,12 @@ struct AnonSocket { /// This flag is set to `true` if the peer's `readbuf` is non-empty at the time /// of closure. peer_lost_data: Cell, + /// A list of thread ids blocked because the buffer was empty. + /// Once another thread writes some bytes, these threads will be unblocked. + blocked_read_tid: RefCell>, + /// A list of thread ids blocked because the buffer was full. + /// Once another thread reads some bytes, these threads will be unblocked. + blocked_write_tid: RefCell>, is_nonblock: bool, } @@ -83,7 +89,7 @@ impl FileDescription for AnonSocket { fn read<'tcx>( &self, - _self_ref: &FileDescriptionRef, + self_ref: &FileDescriptionRef, _communicate_allowed: bool, ptr: Pointer, len: usize, @@ -100,33 +106,21 @@ impl FileDescription for AnonSocket { // corresponding ErrorKind variant. throw_unsup_format!("reading from the write end of a pipe"); }; - if readbuf.borrow().buf.is_empty() { - if self.peer_fd().upgrade().is_none() { - // Socketpair with no peer and empty buffer. - // 0 bytes successfully read indicates end-of-file. - return ecx.return_read_success(ptr, &[], 0, dest); - } else { - if self.is_nonblock { - // Non-blocking socketpair with writer and empty buffer. - // https://linux.die.net/man/2/read - // EAGAIN or EWOULDBLOCK can be returned for socket, - // POSIX.1-2001 allows either error to be returned for this case. - // Since there is no ErrorKind for EAGAIN, WouldBlock is used. - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); - } else { - // Blocking socketpair with writer and empty buffer. - // FIXME: blocking is currently not supported - throw_unsup_format!("socketpair/pipe/pipe2 read: blocking isn't supported yet"); - } - } + + if readbuf.borrow().buf.is_empty() && self.is_nonblock { + // Non-blocking socketpair with writer and empty buffer. + // https://linux.die.net/man/2/read + // EAGAIN or EWOULDBLOCK can be returned for socket, + // POSIX.1-2001 allows either error to be returned for this case. + // Since there is no ErrorKind for EAGAIN, WouldBlock is used. + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } - // TODO: We might need to decide what to do if peer_fd is closed when read is blocked. - anonsocket_read(self, self.peer_fd().upgrade(), len, ptr, dest, ecx) + anonsocket_read(self_ref.downgrade(), len, ptr, dest.clone(), ecx) } fn write<'tcx>( &self, - _self_ref: &FileDescriptionRef, + self_ref: &FileDescriptionRef, _communicate_allowed: bool, ptr: Pointer, len: usize, @@ -153,16 +147,11 @@ impl FileDescription for AnonSocket { }; let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len()); - if available_space == 0 { - if self.is_nonblock { - // Non-blocking socketpair with a full buffer. - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); - } else { - // Blocking socketpair with a full buffer. - throw_unsup_format!("socketpair/pipe/pipe2 write: blocking isn't supported yet"); - } + if available_space == 0 && self.is_nonblock { + // Non-blocking socketpair with a full buffer. + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } - anonsocket_write(available_space, &peer_fd, ptr, len, dest, ecx) + anonsocket_write(self_ref.downgrade(), ptr, len, dest.clone(), ecx) } fn as_unix(&self) -> &dyn UnixFileDescription { @@ -172,81 +161,161 @@ impl FileDescription for AnonSocket { /// Write to AnonSocket based on the space available and return the written byte size. fn anonsocket_write<'tcx>( - available_space: usize, - peer_fd: &FileDescriptionRef, + weak_self_ref: WeakFileDescriptionRef, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, + dest: MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { + let Some(self_ref) = weak_self_ref.upgrade() else { + // FIXME: We should raise a deadlock error if the self_ref upgrade failed. + throw_unsup_format!("This will be a deadlock error in future") + }; + let self_anonsocket = self_ref.downcast::().unwrap(); + let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() else { + // If the upgrade from Weak to Rc fails, it indicates that all read ends have been + // closed. + return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, &dest); + }; let Some(writebuf) = &peer_fd.downcast::().unwrap().readbuf else { // FIXME: This should return EBADF, but there's no nice way to do that as there's no // corresponding ErrorKind variant. throw_unsup_format!("writing to the reading end of a pipe") }; - let mut writebuf = writebuf.borrow_mut(); - // Remember this clock so `read` can synchronize with us. - ecx.release_clock(|clock| { - writebuf.clock.join(clock); - }); - // Do full write / partial write based on the space available. - let actual_write_size = len.min(available_space); - let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - writebuf.buf.extend(&bytes[..actual_write_size]); + let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len()); + + if available_space == 0 { + // Blocking socketpair with a full buffer. + let dest = dest.clone(); + self_anonsocket.blocked_write_tid.borrow_mut().push(ecx.active_thread()); + ecx.block_thread( + BlockReason::UnnamedSocket, + None, + callback!( + @capture<'tcx> { + weak_self_ref: WeakFileDescriptionRef, + ptr: Pointer, + len: usize, + dest: MPlaceTy<'tcx>, + } + @unblock = |this| { + anonsocket_write(weak_self_ref, ptr, len, dest, this) + } + ), + ); + } else { + let mut writebuf = writebuf.borrow_mut(); + // Remember this clock so `read` can synchronize with us. + ecx.release_clock(|clock| { + writebuf.clock.join(clock); + }); + // Do full write / partial write based on the space available. + let actual_write_size = len.min(available_space); + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; + writebuf.buf.extend(&bytes[..actual_write_size]); - // Need to stop accessing peer_fd so that it can be notified. - drop(writebuf); + // Need to stop accessing peer_fd so that it can be notified. + drop(writebuf); - // Notification should be provided for peer fd as it became readable. - // The kernel does this even if the fd was already readable before, so we follow suit. - ecx.check_and_update_readiness(peer_fd)?; + // Notification should be provided for peer fd as it became readable. + // The kernel does this even if the fd was already readable before, so we follow suit. + ecx.check_and_update_readiness(&peer_fd)?; + let peer_anonsocket = peer_fd.downcast::().unwrap(); + // Unblock all threads that are currently blocked on peer_fd's read. + let waiting_threads = std::mem::take(&mut *peer_anonsocket.blocked_read_tid.borrow_mut()); + // FIXME: We can randomize the order of unblocking. + for thread_id in waiting_threads { + ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?; + } - ecx.return_write_success(actual_write_size, dest) + return ecx.return_write_success(actual_write_size, &dest); + } + interp_ok(()) } /// Read from AnonSocket and return the number of bytes read. fn anonsocket_read<'tcx>( - anonsocket: &AnonSocket, - peer_fd: Option, + weak_self_ref: WeakFileDescriptionRef, len: usize, ptr: Pointer, - dest: &MPlaceTy<'tcx>, + dest: MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - let mut bytes = vec![0; len]; + let Some(self_ref) = weak_self_ref.upgrade() else { + // FIXME: We should raise a deadlock error if the self_ref upgrade failed. + throw_unsup_format!("This will be a deadlock error in future") + }; + let self_anonsocket = self_ref.downcast::().unwrap(); - let Some(readbuf) = &anonsocket.readbuf else { + let Some(readbuf) = &self_anonsocket.readbuf else { // FIXME: This should return EBADF, but there's no nice way to do that as there's no // corresponding ErrorKind variant. throw_unsup_format!("reading from the write end of a pipe") }; - let mut readbuf = readbuf.borrow_mut(); - - // Synchronize with all previous writes to this buffer. - // FIXME: this over-synchronizes; a more precise approach would be to - // only sync with the writes whose data we will read. - ecx.acquire_clock(&readbuf.clock); - - // Do full read / partial read based on the space available. - // Conveniently, `read` exists on `VecDeque` and has exactly the desired behavior. - let actual_read_size = readbuf.buf.read(&mut bytes[..]).unwrap(); - - // Need to drop before others can access the readbuf again. - drop(readbuf); - - // A notification should be provided for the peer file description even when it can - // only write 1 byte. This implementation is not compliant with the actual Linux kernel - // implementation. For optimization reasons, the kernel will only mark the file description - // as "writable" when it can write more than a certain number of bytes. Since we - // don't know what that *certain number* is, we will provide a notification every time - // a read is successful. This might result in our epoll emulation providing more - // notifications than the real system. - if let Some(peer_fd) = peer_fd { - ecx.check_and_update_readiness(&peer_fd)?; - } - ecx.return_read_success(ptr, &bytes, actual_read_size, dest) + if readbuf.borrow_mut().buf.is_empty() { + if self_anonsocket.peer_fd().upgrade().is_none() { + // Socketpair with no peer and empty buffer. + // 0 bytes successfully read indicates end-of-file. + return ecx.return_read_success(ptr, &[], 0, &dest); + } else { + // Blocking socketpair with writer and empty buffer. + let weak_self_ref = weak_self_ref.clone(); + self_anonsocket.blocked_read_tid.borrow_mut().push(ecx.active_thread()); + ecx.block_thread( + BlockReason::UnnamedSocket, + None, + callback!( + @capture<'tcx> { + weak_self_ref: WeakFileDescriptionRef, + len: usize, + ptr: Pointer, + dest: MPlaceTy<'tcx>, + } + @unblock = |this| { + anonsocket_read(weak_self_ref, len, ptr, dest, this) + } + ), + ); + } + } else { + let mut bytes = vec![0; len]; + let mut readbuf = readbuf.borrow_mut(); + // Synchronize with all previous writes to this buffer. + // FIXME: this over-synchronizes; a more precise approach would be to + // only sync with the writes whose data we will read. + ecx.acquire_clock(&readbuf.clock); + + // Do full read / partial read based on the space available. + // Conveniently, `read` exists on `VecDeque` and has exactly the desired behavior. + let actual_read_size = readbuf.buf.read(&mut bytes[..]).unwrap(); + + // Need to drop before others can access the readbuf again. + drop(readbuf); + + // A notification should be provided for the peer file description even when it can + // only write 1 byte. This implementation is not compliant with the actual Linux kernel + // implementation. For optimization reasons, the kernel will only mark the file description + // as "writable" when it can write more than a certain number of bytes. Since we + // don't know what that *certain number* is, we will provide a notification every time + // a read is successful. This might result in our epoll emulation providing more + // notifications than the real system. + if let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() { + ecx.check_and_update_readiness(&peer_fd)?; + let peer_anonsocket = peer_fd.downcast::().unwrap(); + // Unblock all threads that are currently blocked on peer_fd's write. + let waiting_threads = + std::mem::take(&mut *peer_anonsocket.blocked_write_tid.borrow_mut()); + // FIXME: We can randomize the order of unblocking. + for thread_id in waiting_threads { + ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?; + } + }; + + return ecx.return_read_success(ptr, &bytes, actual_read_size, &dest); + } + interp_ok(()) } impl UnixFileDescription for AnonSocket { @@ -360,12 +429,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { readbuf: Some(RefCell::new(Buffer::new())), peer_fd: OnceCell::new(), peer_lost_data: Cell::new(false), + blocked_read_tid: RefCell::new(Vec::new()), + blocked_write_tid: RefCell::new(Vec::new()), is_nonblock: is_sock_nonblock, }); let fd1 = fds.new_ref(AnonSocket { readbuf: Some(RefCell::new(Buffer::new())), peer_fd: OnceCell::new(), peer_lost_data: Cell::new(false), + blocked_read_tid: RefCell::new(Vec::new()), + blocked_write_tid: RefCell::new(Vec::new()), is_nonblock: is_sock_nonblock, }); @@ -424,12 +497,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { readbuf: Some(RefCell::new(Buffer::new())), peer_fd: OnceCell::new(), peer_lost_data: Cell::new(false), + blocked_read_tid: RefCell::new(Vec::new()), + blocked_write_tid: RefCell::new(Vec::new()), is_nonblock, }); let fd1 = fds.new_ref(AnonSocket { readbuf: None, peer_fd: OnceCell::new(), peer_lost_data: Cell::new(false), + blocked_read_tid: RefCell::new(Vec::new()), + blocked_write_tid: RefCell::new(Vec::new()), is_nonblock, }); diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs new file mode 100644 index 0000000000000..d3e4c43f2b75c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs @@ -0,0 +1,47 @@ +//@ignore-target: windows # No libc socketpair on Windows +//~^ERROR: deadlocked +//~^^ERROR: deadlocked +// test_race depends on a deterministic schedule. +//@compile-flags: -Zmiri-preemption-rate=0 +//@error-in-other-file: deadlock + +use std::thread; + +// Test the behaviour of a thread being blocked on read, get unblocked, then blocked again. + +// The expected execution is +// 1. Thread 1 blocks. +// 2. Thread 2 blocks. +// 3. Thread 3 unblocks both thread 1 and thread 2. +// 4. Thread 1 reads. +// 5. Thread 2's `read` can never complete -> deadlocked. + +fn main() { + let mut fds = [-1, -1]; + let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; + assert_eq!(res, 0); + let thread1 = thread::spawn(move || { + // Let this thread block on read. + let mut buf: [u8; 3] = [0; 3]; + let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + assert_eq!(res, 3); + assert_eq!(&buf, "abc".as_bytes()); + }); + let thread2 = thread::spawn(move || { + // Let this thread block on read. + let mut buf: [u8; 3] = [0; 3]; + let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + //~^ERROR: deadlocked + assert_eq!(res, 3); + assert_eq!(&buf, "abc".as_bytes()); + }); + let thread3 = thread::spawn(move || { + // Unblock thread1 by writing something. + let data = "abc".as_bytes().as_ptr(); + let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; + assert_eq!(res, 3); + }); + thread1.join().unwrap(); + thread2.join().unwrap(); + thread3.join().unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr new file mode 100644 index 0000000000000..ab807a579db30 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr @@ -0,0 +1,41 @@ +error: deadlock: the evaluated program deadlocked + --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + | +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + | ^ the evaluated program deadlocked + | + = note: BACKTRACE: + = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` + --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC + | +LL | thread2.join().unwrap(); + | ^^^^^^^^^^^^^^ + +error: deadlock: the evaluated program deadlocked + | + = note: the evaluated program deadlocked + = note: (no span available) + = note: BACKTRACE on thread `unnamed-ID`: + +error: deadlock: the evaluated program deadlocked + --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC + | +LL | let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + | ^ the evaluated program deadlocked + | + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC + +error: deadlock: the evaluated program deadlocked + | + = note: the evaluated program deadlocked + = note: (no span available) + = note: BACKTRACE on thread `unnamed-ID`: + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 4 previous errors + diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs new file mode 100644 index 0000000000000..4f951acb2c31a --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs @@ -0,0 +1,49 @@ +//@ignore-target: windows # No libc socketpair on Windows +//~^ERROR: deadlocked +//~^^ERROR: deadlocked +// test_race depends on a deterministic schedule. +//@compile-flags: -Zmiri-preemption-rate=0 +//@error-in-other-file: deadlock + +use std::thread; + +// Test the behaviour of a thread being blocked on write, get unblocked, then blocked again. + +// The expected execution is +// 1. Thread 1 blocks. +// 2. Thread 2 blocks. +// 3. Thread 3 unblocks both thread 1 and thread 2. +// 4. Thread 1 reads. +// 5. Thread 2's `write` can never complete -> deadlocked. +fn main() { + let mut fds = [-1, -1]; + let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; + assert_eq!(res, 0); + let arr1: [u8; 212992] = [1; 212992]; + // Exhaust the space in the buffer so the subsequent write will block. + let res = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) }; + assert_eq!(res, 212992); + let thread1 = thread::spawn(move || { + let data = "abc".as_bytes().as_ptr(); + // The write below will be blocked because the buffer is already full. + let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; + assert_eq!(res, 3); + }); + let thread2 = thread::spawn(move || { + let data = "abc".as_bytes().as_ptr(); + // The write below will be blocked because the buffer is already full. + let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; + //~^ERROR: deadlocked + assert_eq!(res, 3); + }); + let thread3 = thread::spawn(move || { + // Unblock thread1 by freeing up some space. + let mut buf: [u8; 3] = [0; 3]; + let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + assert_eq!(res, 3); + assert_eq!(buf, [1, 1, 1]); + }); + thread1.join().unwrap(); + thread2.join().unwrap(); + thread3.join().unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr new file mode 100644 index 0000000000000..44cda11102db7 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr @@ -0,0 +1,41 @@ +error: deadlock: the evaluated program deadlocked + --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + | +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + | ^ the evaluated program deadlocked + | + = note: BACKTRACE: + = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` + --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC + | +LL | thread2.join().unwrap(); + | ^^^^^^^^^^^^^^ + +error: deadlock: the evaluated program deadlocked + | + = note: the evaluated program deadlocked + = note: (no span available) + = note: BACKTRACE on thread `unnamed-ID`: + +error: deadlock: the evaluated program deadlocked + --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC + | +LL | let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; + | ^ the evaluated program deadlocked + | + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC + +error: deadlock: the evaluated program deadlocked + | + = note: the evaluated program deadlocked + = note: (no span available) + = note: BACKTRACE on thread `unnamed-ID`: + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 4 previous errors + diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs deleted file mode 100644 index ffa4e36f0f4b0..0000000000000 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ignore-target: windows # no libc socketpair on Windows - -// This is temporarily here because blocking on fd is not supported yet. -// When blocking is eventually supported, this will be moved to pass-dep/libc/libc-socketpair - -fn main() { - let mut fds = [-1, -1]; - let _ = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - // The read below will be blocked because the buffer is empty. - let mut buf: [u8; 3] = [0; 3]; - let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; //~ERROR: blocking isn't supported -} diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr index 16892614c63a2..caf23da1150f4 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr @@ -1,10 +1,9 @@ -error: unsupported operation: socketpair/pipe/pipe2 read: blocking isn't supported yet +error: deadlock: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC | LL | let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair/pipe/pipe2 read: blocking isn't supported yet + | ^ the evaluated program deadlocked | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: = note: inside `main` at tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs deleted file mode 100644 index e83197dfc0f90..0000000000000 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ignore-target: windows # no libc socketpair on Windows -// This is temporarily here because blocking on fd is not supported yet. -// When blocking is eventually supported, this will be moved to pass-dep/libc/libc-socketpair -fn main() { - let mut fds = [-1, -1]; - let _ = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - // Write size > buffer capacity - // Used up all the space in the buffer. - let arr1: [u8; 212992] = [1; 212992]; - let _ = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) }; - let data = "abc".as_bytes().as_ptr(); - // The write below will be blocked as the buffer is full. - let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; //~ERROR: blocking isn't supported - let mut buf: [u8; 3] = [0; 3]; - let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; -} diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr index a2fcf87578a49..2dc420d5f1ef4 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr @@ -1,10 +1,9 @@ -error: unsupported operation: socketpair/pipe/pipe2 write: blocking isn't supported yet +error: deadlock: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC | LL | let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair/pipe/pipe2 write: blocking isn't supported yet + | ^ the evaluated program deadlocked | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: = note: inside `main` at tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index 64819e576799f..bbf0e2159530e 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -10,6 +10,8 @@ fn main() { test_socketpair(); test_socketpair_threaded(); test_race(); + test_blocking_read(); + test_blocking_write(); } fn test_socketpair() { @@ -136,3 +138,51 @@ fn test_race() { thread::yield_now(); thread1.join().unwrap(); } + +// Test the behaviour of a socketpair getting blocked on read and subsequently unblocked. +fn test_blocking_read() { + let mut fds = [-1, -1]; + let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; + assert_eq!(res, 0); + let thread1 = thread::spawn(move || { + // Let this thread block on read. + let mut buf: [u8; 3] = [0; 3]; + let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + assert_eq!(res, 3); + assert_eq!(&buf, "abc".as_bytes()); + }); + let thread2 = thread::spawn(move || { + // Unblock thread1 by doing writing something. + let data = "abc".as_bytes().as_ptr(); + let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; + assert_eq!(res, 3); + }); + thread1.join().unwrap(); + thread2.join().unwrap(); +} + +// Test the behaviour of a socketpair getting blocked on write and subsequently unblocked. +fn test_blocking_write() { + let mut fds = [-1, -1]; + let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; + assert_eq!(res, 0); + let arr1: [u8; 212992] = [1; 212992]; + // Exhaust the space in the buffer so the subsequent write will block. + let res = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) }; + assert_eq!(res, 212992); + let thread1 = thread::spawn(move || { + let data = "abc".as_bytes().as_ptr(); + // The write below will be blocked because the buffer is already full. + let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; + assert_eq!(res, 3); + }); + let thread2 = thread::spawn(move || { + // Unblock thread1 by freeing up some space. + let mut buf: [u8; 3] = [0; 3]; + let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + assert_eq!(res, 3); + assert_eq!(buf, [1, 1, 1]); + }); + thread1.join().unwrap(); + thread2.join().unwrap(); +} From e28b1d7c0df7beb64ac634c2a4c4bebd252a46fb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Dec 2024 08:13:02 +0100 Subject: [PATCH 21/25] add warning explaining the limitations of the native code mode --- src/tools/miri/README.md | 23 +++++++++------- src/tools/miri/src/diagnostics.rs | 26 +++++++++++++++++++ src/tools/miri/src/shims/native_lib.rs | 13 ++++++++++ .../native-lib/pass/ptr_read_access.stderr | 18 +++++++++++++ .../native-lib/pass/ptr_write_access.stderr | 18 +++++++++++++ 5 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 src/tools/miri/tests/native-lib/pass/ptr_read_access.stderr create mode 100644 src/tools/miri/tests/native-lib/pass/ptr_write_access.stderr diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 4e30dea18ff4a..8f577295d1750 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -375,16 +375,19 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. * `-Zmiri-native-lib=` is an experimental flag for providing support - for calling native functions from inside the interpreter via FFI. Functions not provided by that - file are still executed via the usual Miri shims. - **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause Undefined Behavior in Miri itself! - And of course, Miri cannot do any checks on the actions taken by the native code. - Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions - working on file descriptors, you will have to replace *all* of them, or the two kinds of - file descriptors will be mixed up. - This is **work in progress**; currently, only integer arguments and return values are - supported (and no, pointer/integer casts to work around this limitation will not work; - they will fail horribly). It also only works on Unix hosts for now. + for calling native functions from inside the interpreter via FFI. The flag is supported only on + Unix systems. Functions not provided by that file are still executed via the usual Miri shims. + **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause Undefined Behavior in + Miri itself! And of course, Miri cannot do any checks on the actions taken by the native code. + Note that Miri has its own handling of file descriptors, so if you want to replace *some* + functions working on file descriptors, you will have to replace *all* of them, or the two kinds of + file descriptors will be mixed up. This is **work in progress**; currently, only integer and + pointers arguments and return values are supported and memory allocated by the native code cannot + be accessed from Rust (only the other way around). Native code must not spawn threads that keep + running in the background after the call has returned to Rust and that access Rust-allocated + memory. Finally, the flag is **unsound** in the sense that Miri stops tracking details such as + initialization and provenance on memory shared with native code, so it is easily possible to write + code that has UB which is missed by Miri. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file inside a directory called ``, and can be processed diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 41b7be37c37d3..6b5646d5473fc 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -126,6 +126,7 @@ pub enum NonHaltingDiagnostic { Int2Ptr { details: bool, }, + NativeCallSharedMem, WeakMemoryOutdatedLoad { ptr: Pointer, }, @@ -602,6 +603,8 @@ impl<'tcx> MiriMachine<'tcx> { RejectedIsolatedOp(_) => ("operation rejected by isolation".to_string(), DiagLevel::Warning), Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning), + NativeCallSharedMem => + ("sharing memory with a native function".to_string(), DiagLevel::Warning), ExternTypeReborrow => ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning), CreatedPointerTag(..) @@ -637,6 +640,7 @@ impl<'tcx> MiriMachine<'tcx> { ProgressReport { .. } => format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), + NativeCallSharedMem => format!("sharing memory with a native function called via FFI"), WeakMemoryOutdatedLoad { ptr } => format!("weak memory emulation: outdated value returned from load at {ptr}"), ExternTypeReborrow => @@ -679,7 +683,29 @@ impl<'tcx> MiriMachine<'tcx> { } v } + NativeCallSharedMem => { + vec![ + note!( + "when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory" + ), + note!( + "in particular, Miri assumes that the native call initializes all memory it has access to" + ), + note!( + "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory" + ), + note!( + "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free" + ), + ] + } ExternTypeReborrow => { + assert!(self.borrow_tracker.as_ref().is_some_and(|b| { + matches!( + b.borrow().borrow_tracker_method(), + BorrowTrackerMethod::StackedBorrows + ) + })); vec![ note!( "`extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code" diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index f18d023677492..345ca3fbcc197 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -1,4 +1,5 @@ //! Implements calling functions from a native library. +use std::cell::RefCell; use std::ops::Deref; use libffi::high::call as ffi; @@ -172,6 +173,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Wildcard pointer, whatever it points to must be already exposed. continue; }; + // The first time this happens at a particular location, print a warning. + thread_local! { + static HAVE_WARNED: RefCell = const { RefCell::new(false) }; + } + HAVE_WARNED.with_borrow_mut(|have_warned| { + if !*have_warned { + // Newly inserted, so first time we see this span. + this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem); + *have_warned = true; + } + }); + this.prepare_for_native_call(alloc_id, prov)?; } } diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.stderr new file mode 100644 index 0000000000000..ab40811a9d1af --- /dev/null +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.stderr @@ -0,0 +1,18 @@ +warning: sharing memory with a native function + --> tests/native-lib/pass/ptr_read_access.rs:LL:CC + | +LL | unsafe { print_pointer(&x) }; + | ^^^^^^^^^^^^^^^^^ sharing memory with a native function called via FFI + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: BACKTRACE: + = note: inside `test_access_pointer` at tests/native-lib/pass/ptr_read_access.rs:LL:CC +note: inside `main` + --> tests/native-lib/pass/ptr_read_access.rs:LL:CC + | +LL | test_access_pointer(); + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.stderr new file mode 100644 index 0000000000000..a059d7740ffb1 --- /dev/null +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.stderr @@ -0,0 +1,18 @@ +warning: sharing memory with a native function + --> tests/native-lib/pass/ptr_write_access.rs:LL:CC + | +LL | unsafe { increment_int(&mut x) }; + | ^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function called via FFI + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: BACKTRACE: + = note: inside `test_increment_int` at tests/native-lib/pass/ptr_write_access.rs:LL:CC +note: inside `main` + --> tests/native-lib/pass/ptr_write_access.rs:LL:CC + | +LL | test_increment_int(); + | ^^^^^^^^^^^^^^^^^^^^ + From 09c8eb5d26c41ecac7b55a4c3cef51bd2bdce507 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 20 Dec 2024 04:54:40 +0000 Subject: [PATCH 22/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index bc92d07323fa3..10108a6fbca0d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -52890e82153cd8716d97a96f47fb6ac99dec65be +214587c89d527dd0ccbe1f2150c737d3bdee67b0 From fafe0ce4ab76b6fa6688f0827649024933b32417 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Dec 2024 11:28:19 +0100 Subject: [PATCH 23/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 10108a6fbca0d..64ce886239634 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -214587c89d527dd0ccbe1f2150c737d3bdee67b0 +8a1f8039a7ded79d3d4fe97b110016d89f2b11e2 From 9659fbcf704d1e78a85d7252757c9d1be84835a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Dec 2024 11:30:38 +0100 Subject: [PATCH 24/25] fmt --- src/tools/miri/src/helpers.rs | 4 +- src/tools/miri/src/machine.rs | 2 +- src/tools/miri/src/shims/foreign_items.rs | 64 +++------ .../src/shims/unix/android/foreign_items.rs | 11 +- .../miri/src/shims/unix/foreign_items.rs | 2 +- .../src/shims/unix/freebsd/foreign_items.rs | 21 +-- .../src/shims/unix/linux/foreign_items.rs | 27 ++-- .../miri/src/shims/unix/linux_like/syscall.rs | 1 - .../src/shims/unix/macos/foreign_items.rs | 60 +++----- .../src/shims/unix/solarish/foreign_items.rs | 27 ++-- .../miri/src/shims/wasi/foreign_items.rs | 6 +- .../miri/src/shims/windows/foreign_items.rs | 135 ++++++------------ src/tools/miri/src/shims/x86/aesni.rs | 12 +- src/tools/miri/src/shims/x86/avx.rs | 48 +++---- src/tools/miri/src/shims/x86/avx2.rs | 54 +++---- src/tools/miri/src/shims/x86/bmi.rs | 5 +- src/tools/miri/src/shims/x86/gfni.rs | 11 +- src/tools/miri/src/shims/x86/mod.rs | 6 +- src/tools/miri/src/shims/x86/sha.rs | 9 +- src/tools/miri/src/shims/x86/sse.rs | 18 +-- src/tools/miri/src/shims/x86/sse2.rs | 36 ++--- src/tools/miri/src/shims/x86/sse3.rs | 6 +- src/tools/miri/src/shims/x86/sse41.rs | 27 ++-- src/tools/miri/src/shims/x86/sse42.rs | 15 +- src/tools/miri/src/shims/x86/ssse3.rs | 15 +- 25 files changed, 211 insertions(+), 411 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 8b9ad3c1ade8f..444ff72513963 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -925,7 +925,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if fn_abi.conv != exp_abi { throw_ub_format!( "calling a function with ABI {:?} using caller ABI {:?}", - exp_abi, fn_abi.conv); + exp_abi, + fn_abi.conv + ); } interp_ok(()) } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 592a54ff50d26..33cefd607646a 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -13,7 +13,6 @@ use rand::{Rng, SeedableRng}; use rustc_abi::{Align, ExternAbi, Size}; use rustc_attr_parsing::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_target::callconv::FnAbi; #[allow(unused)] use rustc_data_structures::static_assert_size; use rustc_middle::mir; @@ -25,6 +24,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::config::InliningThreshold; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{Span, SpanData, Symbol}; +use rustc_target::callconv::FnAbi; use crate::concurrency::cpu_affinity::{self, CpuAffinityMask}; use crate::concurrency::data_race::{self, NaReadType, NaWriteType}; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 7b2a0d6f4d641..8c8850ba7e0a8 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -9,12 +9,11 @@ use rustc_ast::expand::allocator::alloc_error_handler_name; use rustc_hir::def::DefKind; use rustc_hir::def_id::CrateNum; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::{mir, ty}; use rustc_middle::ty::Ty; +use rustc_middle::{mir, ty}; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; - use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; @@ -279,7 +278,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Miri-specific extern functions "miri_start_unwind" => { - let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } @@ -288,7 +287,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.run_provenance_gc(); } "miri_get_alloc_id" => { - let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| { err_machine_stop!(TerminationInfo::Abort(format!( @@ -298,7 +297,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } "miri_print_borrow_state" => { - let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZero::new(id).map(AllocId) @@ -312,8 +311,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_pointer_name" => { // This associates a name to a tag. Very useful for debugging, and also makes // tests more strict. - let [ptr, nth_parent, name] = - this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr, nth_parent, name] = this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let nth_parent = this.read_scalar(nth_parent)?.to_u8()?; let name = this.read_immediate(name)?; @@ -337,8 +335,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.static_roots.push(alloc_id); } "miri_host_to_target_path" => { - let [ptr, out, out_size] = - this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr, out, out_size] = this.check_shim(abi, Conv::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let out = this.read_pointer(out)?; let out_size = this.read_scalar(out_size)?.to_target_usize(this)?; @@ -429,13 +426,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Aborting the process. "exit" => { - let [code] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [code] = this.check_shim(abi, Conv::C, link_name, args)?; let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); } "abort" => { - let [] = this.check_shim(abi, Conv::C , link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -443,8 +439,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Standard C allocation "malloc" => { - let [size] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [size] = this.check_shim(abi, Conv::C, link_name, args)?; let size = this.read_target_usize(size)?; if size <= this.max_size_of_val().bytes() { let res = this.malloc(size, /*zero_init:*/ false)?; @@ -458,8 +453,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "calloc" => { - let [items, elem_size] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [items, elem_size] = this.check_shim(abi, Conv::C, link_name, args)?; let items = this.read_target_usize(items)?; let elem_size = this.read_target_usize(elem_size)?; if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) { @@ -474,14 +468,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "free" => { - let [ptr] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; this.free(ptr)?; } "realloc" => { - let [old_ptr, new_size] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [old_ptr, new_size] = this.check_shim(abi, Conv::C, link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_target_usize(new_size)?; if new_size <= this.max_size_of_val().bytes() { @@ -619,8 +611,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // C memory handling functions "memcmp" => { - let [left, right, n] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [left, right, n] = this.check_shim(abi, Conv::C, link_name, args)?; let left = this.read_pointer(left)?; let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_target_usize(n)?); @@ -644,8 +635,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let [ptr, val, num] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; @@ -671,8 +661,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "memchr" => { - let [ptr, val, num] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; @@ -695,8 +684,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "strlen" => { - let [ptr] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_c_str(ptr)?.len(); @@ -706,8 +694,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "wcslen" => { - let [ptr] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_wchar_t_str(ptr)?.len(); @@ -717,8 +704,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "memcpy" => { - let [ptr_dest, ptr_src, n] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr_dest, ptr_src, n] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; let n = this.read_target_usize(n)?; @@ -732,8 +718,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr_dest, dest)?; } "strcpy" => { - let [ptr_dest, ptr_src] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr_dest, ptr_src] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; @@ -878,8 +863,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "lgammaf_r" => { - let [x, signp] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?; let x = this.read_scalar(x)?.to_f32()?; let signp = this.deref_pointer(signp)?; @@ -890,8 +874,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "lgamma_r" => { - let [x, signp] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?; let x = this.read_scalar(x)?.to_f64()?; let signp = this.deref_pointer(signp)?; @@ -904,8 +887,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // LLVM intrinsics "llvm.prefetch" => { - let [p, rw, loc, ty] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [p, rw, loc, ty] = this.check_shim(abi, Conv::C, link_name, args)?; let _ = this.read_pointer(p)?; let rw = this.read_scalar(rw)?.to_i32()?; @@ -932,7 +914,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm // `{i,u}8x16_popcnt` functions. name if name.starts_with("llvm.ctpop.v") => { - let [op] = this.check_shim(abi, Conv::C , link_name, args)?; + let [op] = this.check_shim(abi, Conv::C, link_name, args)?; let (op, op_len) = this.project_to_simd(op)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 1a2fa7cfc0f68..0e7cf7153f5b3 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -2,8 +2,6 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; - - use crate::shims::unix::android::thread::prctl; use crate::shims::unix::linux_like::epoll::EvalContextExt as _; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; @@ -27,14 +25,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // epoll, eventfd "epoll_create1" => { - let [flag] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [flag] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { - let [epfd, op, fd, event] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } @@ -44,8 +40,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { - let [val, flag] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index ff316e782b0b1..f47a96b10fe58 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -2,8 +2,8 @@ use std::ffi::OsStr; use std::str; use rustc_abi::Size; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; 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 b617e00e5d5ef..5381234e28ca7 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -22,8 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Threading "pthread_set_name_np" => { - let [thread, name] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; let max_len = usize::MAX; // FreeBSD does not seem to have a limit. // FreeBSD's pthread_set_name_np does not return anything. this.pthread_setname_np( @@ -34,8 +33,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "pthread_get_name_np" => { - let [thread, name, len] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; // FreeBSD's pthread_get_name_np does not return anything // and uses strlcpy, which truncates the resulting value, // but always adds a null terminator (except for zero-sized buffers). @@ -52,26 +50,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases // since freebsd 12 the former form can be expected. "stat" | "stat@FBSD_1.0" => { - let [path, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat@FBSD_1.0" => { - let [path, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat@FBSD_1.0" => { - let [fd, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r@FBSD_1.0" => { - let [dirp, entry, result] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } @@ -86,8 +80,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_get_np" if this.frame_in_std() => { - let [_thread, _attr] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } 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 0a9d8a66b7cdc..10af245dcc087 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -36,14 +36,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // File related shims "readdir64" => { - let [dirp] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.linux_solarish_readdir64("dirent64", dirp)?; this.write_scalar(result, dest)?; } "sync_file_range" => { - let [fd, offset, nbytes, flags] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, offset, nbytes, flags] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(result, dest)?; } @@ -56,14 +54,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // epoll, eventfd "epoll_create1" => { - let [flag] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [flag] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { - let [epfd, op, fd, event] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } @@ -73,16 +69,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { - let [val, flag] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } // Threading "pthread_setname_np" => { - let [thread, name] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, @@ -97,8 +91,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. @@ -146,8 +139,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(ptr, dest)?; } "__xpg_strerror_r" => { - let [errnum, buf, buflen] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } @@ -170,8 +162,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { - let [_thread, _attr] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs index 57f10ace6a78b..5fb262e176f0b 100644 --- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs +++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs @@ -2,7 +2,6 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; - use crate::helpers::check_min_arg_count; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; use crate::shims::unix::linux_like::sync::futex; 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 3be6967b7c2fc..aa291639a6db6 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -33,44 +33,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "close$NOCANCEL" => { - let [result] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [result] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.close(result)?; this.write_scalar(result, dest)?; } "stat" | "stat64" | "stat$INODE64" => { - let [path, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { - let [path, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { - let [fd, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { - let [name] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - let [dirp, entry, result] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { - let [path, resolved_path] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } @@ -84,8 +77,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Random data generation "CCRandomGenerateBytes" => { - let [bytes, count] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [bytes, count] = this.check_shim(abi, Conv::C, link_name, args)?; let bytes = this.read_pointer(bytes)?; let count = this.read_target_usize(count)?; let success = this.eval_libc_i32("kCCSuccess"); @@ -101,8 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "mach_timebase_info" => { - let [info] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [info] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(result, dest)?; } @@ -117,8 +108,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?; } "_NSGetExecutablePath" => { - let [buf, bufsize] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; this.check_no_isolation("`_NSGetExecutablePath`")?; let buf_ptr = this.read_pointer(buf)?; @@ -143,8 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "_tlv_atexit" => { - let [dtor, data] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [dtor, data] = this.check_shim(abi, Conv::C, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; @@ -154,15 +143,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "pthread_get_stackaddr_np" => { - let [thread] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread] = this.check_shim(abi, Conv::C, link_name, args)?; this.read_target_usize(thread)?; let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let [thread] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread] = this.check_shim(abi, Conv::C, link_name, args)?; this.read_target_usize(thread)?; let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -170,8 +157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { - let [name] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim(abi, Conv::C, link_name, args)?; // The real implementation has logic in two places: // * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200, @@ -198,8 +184,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of macOS, a truncated name (due to a too small buffer) @@ -224,28 +209,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_unfair_lock_lock" => { - let [lock_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_lock(lock_op)?; } "os_unfair_lock_trylock" => { - let [lock_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_trylock(lock_op, dest)?; } "os_unfair_lock_unlock" => { - let [lock_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_unlock(lock_op)?; } "os_unfair_lock_assert_owner" => { - let [lock_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_assert_owner(lock_op)?; } "os_unfair_lock_assert_not_owner" => { - let [lock_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_assert_not_owner(lock_op)?; } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 63b03c5277ce4..c99e8ae7c6ef0 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -23,8 +23,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Threading "pthread_setname_np" => { - let [thread, name] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; // THREAD_NAME_MAX allows a thread name of 31+1 length // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613 let max_len = 32; @@ -42,8 +41,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; // See https://illumos.org/man/3C/pthread_getname_np for the error codes. let res = match this.pthread_getname_np( this.read_scalar(thread)?, @@ -60,26 +58,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" | "stat64" => { - let [path, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" => { - let [path, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" => { - let [fd, buf] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.macos_fbsd_solaris_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir" => { - let [dirp] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.linux_solarish_readdir64("dirent", dirp)?; this.write_scalar(result, dest)?; } @@ -92,8 +86,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "stack_getbounds" => { - let [stack] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [stack] = this.check_shim(abi, Conv::C, link_name, args)?; let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?; this.write_int_fields_named( @@ -111,8 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pset_info" => { - let [pset, tpe, cpus, list] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [pset, tpe, cpus, list] = this.check_shim(abi, Conv::C, link_name, args)?; // We do not need to handle the current process cpu mask, available_parallelism // implementation pass null anyway. We only care for the number of // cpus. @@ -141,8 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__sysconf_xpg7" => { - let [val] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [val] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index facb6f8ce3a9d..90de62b9e574a 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -22,14 +22,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Allocation "posix_memalign" => { - let [memptr, align, size] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "aligned_alloc" => { - let [align, size] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index dd531c5956f66..fe4d2158ff956 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -108,50 +108,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { - let [name, buf, size] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [name, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(result, dest)?; } "SetEnvironmentVariableW" => { - let [name, value] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [name, value] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(result, dest)?; } "GetEnvironmentStringsW" => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetEnvironmentStringsW()?; this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { - let [env_block] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [env_block] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(result, dest)?; } "GetCurrentDirectoryW" => { - let [size, buf] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [size, buf] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(result, dest)?; } "SetCurrentDirectoryW" => { - let [path] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [path] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(result, dest)?; } "GetUserProfileDirectoryW" => { - let [token, buf, size] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [token, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetUserProfileDirectoryW(token, buf, size)?; this.write_scalar(result, dest)?; } "GetCurrentProcessId" => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.GetCurrentProcessId()?; this.write_scalar(result, dest)?; } @@ -257,8 +249,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "HeapAlloc" => { - let [handle, flags, size] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle, flags, size] = this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(handle)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_target_usize(size)?; @@ -281,8 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr, dest)?; } "HeapFree" => { - let [handle, flags, ptr] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle, flags, ptr] = this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_pointer(ptr)?; @@ -314,8 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(new_ptr, dest)?; } "LocalFree" => { - let [ptr] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [ptr] = this.check_shim(abi, sys_conv, link_name, args)?; let ptr = this.read_pointer(ptr)?; // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL." // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree) @@ -327,14 +316,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // errno "SetLastError" => { - let [error] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [error] = this.check_shim(abi, sys_conv, link_name, args)?; let error = this.read_scalar(error)?; this.set_last_error(error)?; } "GetLastError" => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } @@ -342,8 +329,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "GetSystemInfo" => { // Also called from `page_size` crate. - let [system_info] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [system_info] = this.check_shim(abi, sys_conv, link_name, args)?; let system_info = this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?; // Initialize with `0`. @@ -366,22 +352,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let [key] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [key] = this.check_shim(abi, sys_conv, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let [key, new_ptr] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [key, new_ptr] = this.check_shim(abi, sys_conv, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -401,8 +384,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Access to command-line arguments "GetCommandLineW" => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; this.write_pointer( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -412,27 +394,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Time related shims "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => { #[allow(non_snake_case)] - let [LPFILETIME] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [LPFILETIME] = this.check_shim(abi, sys_conv, link_name, args)?; this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] - let [lpPerformanceCount] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [lpPerformanceCount] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(result, dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] - let [lpFrequency] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [lpFrequency] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(result, dest)?; } "Sleep" => { - let [timeout] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [timeout] = this.check_shim(abi, sys_conv, link_name, args)?; this.Sleep(timeout)?; } @@ -456,8 +434,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?; } "InitOnceComplete" => { - let [ptr, flags, context] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [ptr, flags, context] = this.check_shim(abi, sys_conv, link_name, args)?; let result = this.InitOnceComplete(ptr, flags, context)?; this.write_scalar(result, dest)?; } @@ -468,14 +445,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?; } "WakeByAddressSingle" => { - let [ptr_op] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?; this.WakeByAddressSingle(ptr_op)?; } "WakeByAddressAll" => { - let [ptr_op] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?; this.WakeByAddressAll(ptr_op)?; } @@ -483,8 +458,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] - let [hModule, lpProcName] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [hModule, lpProcName] = this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(hModule)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; if let Ok(name) = str::from_utf8(name) @@ -508,15 +482,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; } "WaitForSingleObject" => { - let [handle, timeout] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?; let ret = this.WaitForSingleObject(handle, timeout)?; this.write_scalar(ret, dest)?; } "GetCurrentThread" => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; this.write_scalar( Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), @@ -524,8 +496,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "SetThreadDescription" => { - let [handle, name] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?; let handle = this.read_scalar(handle)?; let name = this.read_wide_str(this.read_pointer(name)?)?; @@ -549,8 +520,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "GetThreadDescription" => { - let [handle, name_ptr] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?; let handle = this.read_scalar(handle)?; let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name @@ -581,16 +551,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "ExitProcess" => { - let [code] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [code] = this.check_shim(abi, sys_conv, link_name, args)?; let code = this.read_scalar(code)?.to_u32()?; throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); } "SystemFunction036" => { // used by getrandom 0.1 // This is really 'RtlGenRandom'. - let [ptr, len] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -598,8 +566,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "ProcessPrng" => { // used by `std` - let [ptr, len] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -642,8 +609,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let [console, buffer_info] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [console, buffer_info] = this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(console)?; // FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std this.deref_pointer(buffer_info)?; @@ -652,8 +618,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "GetStdHandle" => { - let [which] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [which] = this.check_shim(abi, sys_conv, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `NtWriteFile` which // one it is. This is very fake, but libtest needs it so we cannot make it a @@ -662,16 +627,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?; } "CloseHandle" => { - let [handle] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle] = this.check_shim(abi, sys_conv, link_name, args)?; let ret = this.CloseHandle(handle)?; this.write_scalar(ret, dest)?; } "GetModuleFileNameW" => { - let [handle, filename, size] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?; this.check_no_isolation("`GetModuleFileNameW`")?; let handle = this.read_target_usize(handle)?; @@ -740,16 +703,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; // Just fake a HANDLE // It's fine to not use the Handle type here because its a stub this.write_int(1, dest)?; } "GetModuleHandleA" if this.frame_in_std() => { #[allow(non_snake_case)] - let [_lpModuleName] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [_lpModuleName] = this.check_shim(abi, sys_conv, link_name, args)?; // We need to return something non-null here to make `compat_fn!` work. this.write_int(1, dest)?; } @@ -761,8 +722,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "GetConsoleMode" if this.frame_in_std() => { - let [console, mode] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(console)?; this.deref_pointer(mode)?; // Indicate an error. @@ -770,29 +730,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetFileType" if this.frame_in_std() => { #[allow(non_snake_case)] - let [_hFile] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [_hFile] = this.check_shim(abi, sys_conv, link_name, args)?; // Return unknown file type. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { #[allow(non_snake_case)] - let [_First, _Handler] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [_First, _Handler] = this.check_shim(abi, sys_conv, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { #[allow(non_snake_case)] - let [_StackSizeInBytes] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [_StackSizeInBytes] = this.check_shim(abi, sys_conv, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } // this is only callable from std because we know that std ignores the return value "SwitchToThread" if this.frame_in_std() => { - let [] = - this.check_shim(abi, sys_conv, link_name, args)?; + let [] = this.check_shim(abi, sys_conv, link_name, args)?; this.yield_active_thread(); @@ -811,8 +767,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } // This function looks and behaves excatly like miri_start_unwind. - let [payload] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [payload] = this.check_shim(abi, Conv::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index a89a2bb0cd082..c6784db67fb8e 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -26,8 +26,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128 "aesdec" | "aesdec.256" | "aesdec.512" => { - let [state, key] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let key = aes::Block::from(key.to_le_bytes()); let mut state = aes::Block::from(state.to_le_bytes()); @@ -43,8 +42,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128 "aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => { - let [state, key] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let mut state = aes::Block::from(state.to_le_bytes()); @@ -68,8 +66,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128 "aesenc" | "aesenc.256" | "aesenc.512" => { - let [state, key] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let key = aes::Block::from(key.to_le_bytes()); let mut state = aes::Block::from(state.to_le_bytes()); @@ -85,8 +82,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128 "aesenclast" | "aesenclast.256" | "aesenclast.512" => { - let [state, key] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let mut state = aes::Block::from(state.to_le_bytes()); // `aes::hazmat::cipher_round` does the following operations: diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 07bbd0731d81c..3aeb2b429dad5 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -33,8 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.ps.256" | "max.ps.256" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.ps.256" => FloatBinOp::Min, @@ -46,8 +45,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement _mm256_min_pd and _mm256_max_pd functions. "min.pd.256" | "max.pd.256" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.pd.256" => FloatBinOp::Min, @@ -60,16 +58,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_round_ps function. // Rounds the elements of `op` according to `rounding`. "round.ps.256" => { - let [op, rounding] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } // Used to implement the _mm256_round_pd function. // Rounds the elements of `op` according to `rounding`. "round.pd.256" => { - let [op, rounding] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -88,8 +84,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement the _mm256_dp_ps function. "dp.ps.256" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; conditional_dot_product(this, left, right, imm, dest)?; } @@ -97,8 +92,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Horizontally add/subtract adjacent floating point values // in `left` and `right`. "hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add, @@ -113,8 +107,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and `right`. For each component, returns 0 if false or u32::MAX // if true. "cmp.ps.256" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -126,8 +119,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and `right`. For each component, returns 0 if false or u64::MAX // if true. "cmp.pd.256" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -156,8 +148,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // sequence of 4-element arrays, and we shuffle each of these arrays, where // `control` determines which element of the current `data` array is written. "vpermilvar.ps" | "vpermilvar.ps.256" => { - let [data, control] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?; let (data, data_len) = this.project_to_simd(data)?; let (control, control_len) = this.project_to_simd(control)?; @@ -190,8 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // where `right` determines which element of the current `left` array is // written. "vpermilvar.pd" | "vpermilvar.pd.256" => { - let [data, control] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?; let (data, data_len) = this.project_to_simd(data)?; let (control, control_len) = this.project_to_simd(control)?; @@ -223,8 +213,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For each 128-bit element of `dest`, copies one from `left`, `right` or // zero, according to `imm`. "vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; assert_eq!(dest.layout, left.layout); assert_eq!(dest.layout, right.layout); @@ -267,8 +256,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is // loaded. "maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => { - let [ptr, mask] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?; mask_load(this, ptr, mask, dest)?; } @@ -278,8 +266,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is stored into `ptr.wapping_add(i)`. // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. "maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => { - let [ptr, mask, value] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?; mask_store(this, ptr, mask, value)?; } @@ -289,8 +276,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the data crosses a cache line, but for Miri this is just a regular // unaligned read. "ldu.dq.256" => { - let [src_ptr] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?; let src_ptr = this.read_pointer(src_ptr)?; let dest = dest.force_mplace(this)?; @@ -302,8 +288,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Tests `op & mask == 0`, `op & mask == mask` or // `op & mask != 0 && op & mask != mask` "ptestz.256" | "ptestc.256" | "ptestnzc.256" => { - let [op, mask] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; let res = match unprefixed_name { @@ -326,8 +311,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestz.pd" | "vtestc.pd" | "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256" | "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => { - let [op, mask] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let (direct, negated) = test_high_bits_masked(this, op, mask)?; let res = match unprefixed_name { diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 76e4b06d5cfd2..c79899285cd44 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -36,8 +36,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Horizontally add / add with saturation / subtract adjacent 16/32-bit // integer values in `left` and `right`. "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (which, saturating) = match unprefixed_name { "phadd.w" | "phadd.d" => (mir::BinOp::Add, false), @@ -115,8 +114,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate signed 32-bit integers. Horizontally add adjacent pairs of // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -152,8 +150,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the saturating sum of the products with indices `2*i` and `2*i+1` // produces the output at index `i`. "pmadd.ub.sw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -187,8 +184,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is // loaded. "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => { - let [ptr, mask] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?; mask_load(this, ptr, mask, dest)?; } @@ -198,8 +194,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is stored into `ptr.wapping_add(i)`. // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => { - let [ptr, mask, value] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?; mask_store(this, ptr, mask, value)?; } @@ -210,8 +205,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // offsets specified in `imm`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8 "mpsadbw" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; mpsadbw(this, left, right, imm, dest)?; } @@ -222,8 +216,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 1 and then taking the bits `1..=16`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16 "pmul.hr.sw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; pmulhrsw(this, left, right, dest)?; } @@ -231,8 +224,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit integer vectors to a single 8-bit integer // vector with signed saturation. "packsswb" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packsswb(this, left, right, dest)?; } @@ -240,8 +232,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 32-bit integer vectors to a single 16-bit integer // vector with signed saturation. "packssdw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packssdw(this, left, right, dest)?; } @@ -249,8 +240,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit signed integer vectors to a single 8-bit // unsigned integer vector with saturation. "packuswb" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packuswb(this, left, right, dest)?; } @@ -258,8 +248,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Concatenates two 32-bit signed integer vectors and converts // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packusdw(this, left, right, dest)?; } @@ -268,8 +257,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles `left` using the three low bits of each element of `right` // as indices. "permd" | "permps" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -289,8 +277,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_permute2x128_si256 function. // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern. "vperm2i128" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; assert_eq!(left.layout.size.bits(), 256); assert_eq!(right.layout.size.bits(), 256); @@ -327,8 +314,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // in `dest`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8 "psad.bw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -360,8 +346,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles bytes from `left` using `right` as pattern. // Each 128-bit block is shuffled independently. "pshuf.b" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -392,8 +377,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is writen to the corresponding output element. // Basically, we multiply `left` with `right.signum()`. "psign.b" | "psign.w" | "psign.d" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; psign(this, left, right, dest)?; } @@ -407,8 +391,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is copied to remaining bits. "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -423,8 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // (except _mm{,256}_srav_epi64, which are not available in AVX2). "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256" | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left, diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs index b528076473841..8af59df0a68ba 100644 --- a/src/tools/miri/src/shims/x86/bmi.rs +++ b/src/tools/miri/src/shims/x86/bmi.rs @@ -1,5 +1,5 @@ -use rustc_span::Symbol; use rustc_middle::ty::Ty; +use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -34,8 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NotSupported); } - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let left = this.read_scalar(left)?; let right = this.read_scalar(right)?; diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs index 48718ea609c4f..4774ec9f9d8f5 100644 --- a/src/tools/miri/src/shims/x86/gfni.rs +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -1,5 +1,5 @@ -use rustc_span::Symbol; use rustc_middle::ty::Ty; +use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; use crate::*; @@ -30,16 +30,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See `affine_transform` for details. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_ "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => { - let [left, right, imm8] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?; affine_transform(this, left, right, imm8, dest, /* inverse */ false)?; } // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions. // See `affine_transform` for details. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => { - let [left, right, imm8] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?; affine_transform(this, left, right, imm8, dest, /* inverse */ true)?; } // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions. @@ -48,8 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 13439f421286c..e57217dc6f299 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -68,8 +68,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if is_u64 && this.tcx.sess.target.arch != "x86_64" { return interp_ok(EmulateItemResult::NotSupported); } - let [c_in, a, b, out] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [c_in, a, b, out] = this.check_shim(abi, Conv::C, link_name, args)?; let out = this.deref_pointer_as( out, if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 }, @@ -105,8 +104,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { len = 8; } - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; pclmulqdq(this, left, right, imm, dest, len)?; } diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs index 07cc87a35bf5c..6d2c151243ca1 100644 --- a/src/tools/miri/src/shims/x86/sha.rs +++ b/src/tools/miri/src/shims/x86/sha.rs @@ -52,8 +52,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match unprefixed_name { // Used to implement the _mm_sha256rnds2_epu32 function. "256rnds2" => { - let [a, b, k] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [a, b, k] = this.check_shim(abi, Conv::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; @@ -74,8 +73,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement the _mm_sha256msg1_epu32 function. "256msg1" => { - let [a, b] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; @@ -93,8 +91,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement the _mm_sha256msg2_epu32 function. "256msg2" => { - let [a, b] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index e13265fba4f0d..fd7aba2437a5a 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -33,8 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Performs the operations on the first component of `left` and // `right` and copies the remaining components from `left`. "min.ss" | "max.ss" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.ss" => FloatBinOp::Min, @@ -50,8 +49,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.ps" | "max.ps" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.ps" => FloatBinOp::Min, @@ -97,8 +95,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions // with hard-coded operations. "cmp.ss" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -114,8 +111,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions // with hard-coded operations. "cmp.ps" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -128,8 +124,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss" | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss" | "ucomineq.ss" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -185,8 +180,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // are copied from `left`. // https://www.felixcloutier.com/x86/cvtsi2ss "cvtsi2ss" | "cvtsi642ss" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 959590e9791fd..e0695b7cb7b7a 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -40,8 +40,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate signed 32-bit integers. Horizontally add adjacent pairs of // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -79,8 +78,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8 "psad.bw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -118,8 +116,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is copied to remaining bits. "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -171,8 +168,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit integer vectors to a single 8-bit integer // vector with signed saturation. "packsswb.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packsswb(this, left, right, dest)?; } @@ -180,8 +176,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit signed integer vectors to a single 8-bit // unsigned integer vector with saturation. "packuswb.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packuswb(this, left, right, dest)?; } @@ -189,8 +184,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 32-bit integer vectors to a single 16-bit integer // vector with signed saturation. "packssdw.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packssdw(this, left, right, dest)?; } @@ -200,8 +194,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.sd" | "max.sd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.sd" => FloatBinOp::Min, @@ -217,8 +210,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.pd" | "max.pd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "min.pd" => FloatBinOp::Min, @@ -237,8 +229,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions // with hard-coded operations. "cmp.sd" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -254,8 +245,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions // with hard-coded operations. "cmp.pd" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -268,8 +258,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd" | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd" | "ucomineq.sd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -323,8 +312,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts the first f64/f32 from `right` to f32/f64 and copies // the remaining elements from `left` "cvtsd2ss" | "cvtss2sd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, _) = this.project_to_simd(right)?; diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index 4ebd0240b1d3e..60b7764a01e9d 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -25,8 +25,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Horizontally add/subtract adjacent floating point values // in `left` and `right`. "hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let which = match unprefixed_name { "hadd.ps" | "hadd.pd" => mir::BinOp::Add, @@ -42,8 +41,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the data crosses a cache line, but for Miri this is just a regular // unaligned read. "ldu.dq" => { - let [src_ptr] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?; let src_ptr = this.read_pointer(src_ptr)?; let dest = dest.force_mplace(this)?; diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 41b7feab857bb..93d689a3044e3 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -27,8 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // bits `4..=5` if `imm`, and `i`th bit specifies whether element // `i` is zeroed. "insertps" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -63,8 +62,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Concatenates two 32-bit signed integer vectors and converts // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; packusdw(this, left, right, dest)?; } @@ -74,8 +72,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // products, and conditionally stores the sum in `dest` using the low // 4 bits of `imm`. "dpps" | "dppd" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; conditional_dot_product(this, left, right, imm, dest)?; } @@ -83,16 +80,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // functions. Rounds the first element of `right` according to `rounding` // and copies the remaining elements from `left`. "round.ss" => { - let [left, right, rounding] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; round_first::(this, left, right, rounding, dest)?; } // Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps // functions. Rounds the elements of `op` according to `rounding`. "round.ps" => { - let [op, rounding] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -100,16 +95,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // functions. Rounds the first element of `right` according to `rounding` // and copies the remaining elements from `left`. "round.sd" => { - let [left, right, rounding] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; round_first::(this, left, right, rounding, dest)?; } // Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd // functions. Rounds the elements of `op` according to `rounding`. "round.pd" => { - let [op, rounding] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -151,8 +144,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // offsets specified in `imm`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8 "mpsadbw" => { - let [left, right, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; mpsadbw(this, left, right, imm, dest)?; } @@ -161,8 +153,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Tests `(op & mask) == 0`, `(op & mask) == mask` or // `(op & mask) != 0 && (op & mask) != mask` "ptestz" | "ptestc" | "ptestnzc" => { - let [op, mask] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; let res = match unprefixed_name { diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 6ac69d22a9340..02336a722f7ed 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -223,8 +223,7 @@ fn deconstruct_args<'tcx>( }; if is_explicit { - let [str1, len1, str2, len2, imm] = - ecx.check_shim(abi, Conv::C, link_name, args)?; + let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?; let imm = ecx.read_scalar(imm)?.to_u8()?; let default_len = default_len::(imm); @@ -237,8 +236,7 @@ fn deconstruct_args<'tcx>( interp_ok((str1, str2, Some((len1, len2)), imm)) } else { - let [str1, str2, imm] = - ecx.check_shim(abi, Conv::C, link_name, args)?; + let [str1, str2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?; let imm = ecx.read_scalar(imm)?.to_u8()?; let array_layout = array_layout_fn(ecx, imm)?; @@ -388,8 +386,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // search for a null terminator (see `deconstruct_args` for more details). // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925 "pcmpistriz128" | "pcmpistris128" => { - let [str1, str2, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [str1, str2, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let imm = this.read_scalar(imm)?.to_u8()?; let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 }; @@ -409,8 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // than 16 for byte-sized operands or 8 for word-sized operands. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047 "pcmpestriz128" | "pcmpestris128" => { - let [_, len1, _, len2, imm] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [_, len1, _, len2, imm] = this.check_shim(abi, Conv::C, link_name, args)?; let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 }; let len = this.read_scalar(len)?.to_i32()?; let imm = this.read_scalar(imm)?.to_u8()?; @@ -437,8 +433,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NotSupported); } - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let left = this.read_scalar(left)?; let right = this.read_scalar(right)?; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index d3971d0c92f1d..f3e9ac0e5dc99 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -32,8 +32,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles bytes from `left` using `right` as pattern. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8 "pshuf.b.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -62,8 +61,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // integer values in `left` and `right`. "phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128" | "phsub.d.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (which, saturating) = match unprefixed_name { "phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false), @@ -82,8 +80,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // produces the output at index `i`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16 "pmadd.ub.sw.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -118,8 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 1 and then taking the bits `1..=16`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16 "pmul.hr.sw.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; pmulhrsw(this, left, right, dest)?; } @@ -129,8 +125,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is writen to the corresponding output element. // Basically, we multiply `left` with `right.signum()`. "psign.b.128" | "psign.w.128" | "psign.d.128" => { - let [left, right] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; psign(this, left, right, dest)?; } From 9dac973f8406fdf551bb2f0374a429c48729cb55 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 21 Dec 2024 05:01:56 +0000 Subject: [PATCH 25/25] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 64ce886239634..24bef6026d4ce 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -8a1f8039a7ded79d3d4fe97b110016d89f2b11e2 +13170cd787cb733ed24842ee825bcbd98dc01476