From b07c1f7f4d46f083725a03f85a3c6cd3447267ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 13 Mar 2024 15:09:39 +0100 Subject: [PATCH 01/47] Improve several `Read` implementations --- library/std/src/io/cursor.rs | 21 +++++++++++++++++++++ library/std/src/io/impls.rs | 4 +++- library/std/src/process.rs | 4 ++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 49dde828c1fc4..c4e97fc45ffb9 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -364,6 +364,27 @@ where self.pos += n as u64; Ok(()) } + + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + let content = self.remaining_slice(); + let len = content.len(); + buf.try_reserve(len)?; + buf.extend_from_slice(content); + self.pos += len as u64; + + Ok(len) + } + + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + let content = + crate::str::from_utf8(self.remaining_slice()).map_err(|_| io::Error::INVALID_UTF8)?; + let len = content.len(); + buf.try_reserve(len)?; + buf.push_str(content); + self.pos += len as u64; + + Ok(len) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index dd7e0725176e8..9f9ee4af5c864 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -329,8 +329,9 @@ impl Read for &[u8] { #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { let content = str::from_utf8(self).map_err(|_| io::Error::INVALID_UTF8)?; - buf.push_str(content); let len = self.len(); + buf.try_reserve(len)?; + buf.push_str(content); *self = &self[len..]; Ok(len) } @@ -478,6 +479,7 @@ impl Read for VecDeque { let len = self.len(); let content = self.make_contiguous(); let string = str::from_utf8(content).map_err(|_| io::Error::INVALID_UTF8)?; + buf.try_reserve(len)?; buf.push_str(string); self.clear(); Ok(len) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 69cc61b30efe9..ab282135d1a90 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -486,6 +486,10 @@ impl Read for ChildStderr { fn is_read_vectored(&self) -> bool { self.inner.is_read_vectored() } + + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.inner.read_to_end(buf) + } } impl AsInner for ChildStderr { From 23211b638a78bc7b3e69b8e8cdd25abebeb0f7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Thu, 14 Mar 2024 11:20:59 +0100 Subject: [PATCH 02/47] `VecDeque::read_to_string`: avoid making the slices contiguous --- library/std/src/io/impls.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 9f9ee4af5c864..46f04c7cd3957 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -474,15 +474,8 @@ impl Read for VecDeque { #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { - // We have to use a single contiguous slice because the `VecDequeue` might be split in the - // middle of an UTF-8 character. - let len = self.len(); - let content = self.make_contiguous(); - let string = str::from_utf8(content).map_err(|_| io::Error::INVALID_UTF8)?; - buf.try_reserve(len)?; - buf.push_str(string); - self.clear(); - Ok(len) + // SAFETY: We only append to the buffer + unsafe { io::append_to_string(buf, |buf| self.read_to_end(buf)) } } } From 2e3ee230220cc81b159d99d833cba46c667e3321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 10 Apr 2024 19:16:31 +0200 Subject: [PATCH 03/47] Avoid panicking branch in `append_to_string` --- library/std/src/io/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 98973a43e1ded..450fa43ebea95 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -384,7 +384,10 @@ where { let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; let ret = f(g.buf); - if str::from_utf8(&g.buf[g.len..]).is_err() { + + // SAFETY: the caller promises to only append data to `buf` + let appended = g.buf.get_unchecked(g.len..); + if str::from_utf8(appended).is_err() { ret.and_then(|_| Err(Error::INVALID_UTF8)) } else { g.len = g.buf.len(); From 2681edf93436a31ed0cfe127d8877c236627ffa3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Apr 2024 08:57:55 +0200 Subject: [PATCH 04/47] josh rustc-pull: check that no new root commits get created --- src/tools/miri/miri-script/src/commands.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 66707dee5e75e..575bf4a15dfd0 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -257,12 +257,26 @@ impl Command { }) .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?; + // This should not add any new root commits. So count those before and after merging. + let num_roots = || -> Result { + Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count") + .read() + .context("failed to determine the number of root commits")? + .parse::()?) + }; + let num_roots_before = num_roots()?; + // Merge the fetched commit. const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc"; cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}") .run() .context("FAILED to merge new commits, something went wrong")?; + // Check that the number of roots did not increase. + if num_roots()? != num_roots_before { + bail!("Josh created a new root commit. This is probably not the history you want."); + } + drop(josh); Ok(()) } From 39f7a46d63cf71bfd71926e797eb6f5b20d6b05f Mon Sep 17 00:00:00 2001 From: Hamir Mahal Date: Sat, 27 Apr 2024 00:15:39 -0700 Subject: [PATCH 05/47] fix: usage of `deprecated` version of `Node.js` --- src/tools/miri/.github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 0af334a654b40..3f714fc93201a 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: # over time). - name: Add cache for cargo id: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | # Taken from . @@ -95,7 +95,7 @@ jobs: # over time). - name: Add cache for cargo id: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | # Taken from . From ee47a8e6b610626034f89b4e04132857f5bb2127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Sat, 27 Apr 2024 16:23:44 +0200 Subject: [PATCH 06/47] Add doc comment to `pack_generic` --- src/tools/miri/src/shims/x86/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index cf4d6a04bec87..e04519d9c0ee5 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1127,6 +1127,13 @@ fn pmulhrsw<'tcx>( Ok(()) } +/// Packs two N-bit integer vectors to a single N/2-bit integers. +/// +/// The conversion from N-bit to N/2-bit should be provided by `f`. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). fn pack_generic<'tcx>( this: &mut crate::MiriInterpCx<'_, 'tcx>, left: &OpTy<'tcx, Provenance>, From b3b1b498b9f98c229d90c33c1ae87d6eb4758291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Sat, 27 Apr 2024 16:41:27 +0200 Subject: [PATCH 07/47] Clarify behavior of AVX2 gather when dest and offsets have different numbers of elements --- src/tools/miri/src/shims/x86/avx2.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index bbf53f9f1e5d0..ba361ec65584e 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -71,6 +71,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (dest, dest_len) = this.mplace_to_simd(dest)?; // There are cases like dest: i32x4, offsets: i64x2 + // If dest has more elements than offset, extra dest elements are filled with zero. + // If offsets has more elements than dest, extra offsets are ignored. let actual_len = dest_len.min(offsets_len); assert_eq!(dest_len, mask_len); From b26153555f623b5c436695b76fa536f449fd3424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Sat, 27 Apr 2024 17:43:39 +0200 Subject: [PATCH 08/47] Do not implement x86 SIMD abs with host integers --- src/tools/miri/src/shims/x86/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index e04519d9c0ee5..9a36286a75531 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -739,14 +739,20 @@ fn int_abs<'tcx>( assert_eq!(op_len, dest_len); + let zero = ImmTy::from_int(0, op.layout.field(this, 0)); + for i in 0..dest_len { - let op = this.read_scalar(&this.project_index(&op, i)?)?; + let op = this.read_immediate(&this.project_index(&op, i)?)?; let dest = this.project_index(&dest, i)?; - // Converting to a host "i128" works since the input is always signed. - let res = op.to_int(dest.layout.size)?.unsigned_abs(); + let lt_zero = this.wrapping_binary_op(mir::BinOp::Lt, &op, &zero)?; + let res = if lt_zero.to_scalar().to_bool()? { + this.wrapping_unary_op(mir::UnOp::Neg, &op)? + } else { + op + }; - this.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?; + this.write_immediate(*res, &dest)?; } Ok(()) From b5482aad01e1bc48a5eacd1e1244470bfb2ba09f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Apr 2024 09:38:54 +0200 Subject: [PATCH 09/47] file descriptors: make write take &mut self --- src/tools/miri/src/shims/unix/fd.rs | 16 ++++++++-------- src/tools/miri/src/shims/unix/fs.rs | 4 ++-- src/tools/miri/src/shims/unix/linux/eventfd.rs | 14 +++++--------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index a5fe38b902de8..18a41f6c667ca 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -25,7 +25,7 @@ pub trait FileDescriptor: std::fmt::Debug + Any { } fn write<'tcx>( - &self, + &mut self, _communicate_allowed: bool, _bytes: &[u8], _tcx: TyCtxt<'tcx>, @@ -103,13 +103,13 @@ impl FileDescriptor for io::Stdout { } fn write<'tcx>( - &self, + &mut self, _communicate_allowed: bool, bytes: &[u8], _tcx: TyCtxt<'tcx>, ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. - let result = Write::write(&mut { self }, bytes); + let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted // program, we want it to correspond to a write() syscall on @@ -135,7 +135,7 @@ impl FileDescriptor for io::Stderr { } fn write<'tcx>( - &self, + &mut self, _communicate_allowed: bool, bytes: &[u8], _tcx: TyCtxt<'tcx>, @@ -164,7 +164,7 @@ impl FileDescriptor for NullOutput { } fn write<'tcx>( - &self, + &mut self, _communicate_allowed: bool, bytes: &[u8], _tcx: TyCtxt<'tcx>, @@ -418,10 +418,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .min(u64::try_from(isize::MAX).unwrap()); let communicate = this.machine.communicate(); - if let Some(file_descriptor) = this.machine.fds.get(fd) { - let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?; + let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned(); + if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { let result = file_descriptor - .write(communicate, bytes, *this.tcx)? + .write(communicate, &bytes, *this.tcx)? .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index ebf9f43c19ef6..0bf0e3d52c3c1 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -39,13 +39,13 @@ impl FileDescriptor for FileHandle { } fn write<'tcx>( - &self, + &mut self, communicate_allowed: bool, bytes: &[u8], _tcx: TyCtxt<'tcx>, ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - Ok((&mut &self.file).write(bytes)) + Ok(self.file.write(bytes)) } fn seek<'tcx>( diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index 0f28b69ac4a8e..452527017feb3 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -1,6 +1,5 @@ //! Linux `eventfd` implementation. //! Currently just a stub. -use std::cell::Cell; use std::io; use rustc_middle::ty::TyCtxt; @@ -20,7 +19,7 @@ use crate::*; struct Event { /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the /// kernel. This counter is initialized with the value specified in the argument initval. - val: Cell, + val: u64, } impl FileDescriptor for Event { @@ -30,7 +29,7 @@ impl FileDescriptor for Event { fn dup(&mut self) -> io::Result> { // FIXME: this is wrong, the new and old FD should refer to the same event object! - Ok(Box::new(Event { val: self.val.clone() })) + Ok(Box::new(Event { val: self.val })) } fn close<'tcx>( @@ -53,12 +52,11 @@ impl FileDescriptor for Event { /// supplied buffer is less than 8 bytes, or if an attempt is /// made to write the value 0xffffffffffffffff. fn write<'tcx>( - &self, + &mut self, _communicate_allowed: bool, bytes: &[u8], tcx: TyCtxt<'tcx>, ) -> InterpResult<'tcx, io::Result> { - let v1 = self.val.get(); let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size // Convert from target endianness to host endianness. let num = match tcx.sess.target.endian { @@ -67,9 +65,7 @@ impl FileDescriptor for Event { }; // FIXME handle blocking when addition results in exceeding the max u64 value // or fail with EAGAIN if the file descriptor is nonblocking. - let v2 = v1.checked_add(num).unwrap(); - self.val.set(v2); - assert_eq!(8, bytes.len()); + self.val = self.val.checked_add(num).unwrap(); Ok(Ok(8)) } } @@ -119,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); } - let fd = this.machine.fds.insert_fd(Box::new(Event { val: Cell::new(val.into()) })); + let fd = this.machine.fds.insert_fd(Box::new(Event { val: val.into() })); Ok(Scalar::from_i32(fd)) } } From 622f697f5dbb1489eb568638fd3f07a477a51958 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 27 Apr 2024 14:55:39 -0400 Subject: [PATCH 10/47] Use the interpreted program's TZ variable in localtime_r --- src/tools/miri/Cargo.lock | 201 +++++++++--------------- src/tools/miri/Cargo.toml | 3 +- src/tools/miri/src/shims/env.rs | 15 +- src/tools/miri/src/shims/time.rs | 26 ++- src/tools/miri/src/shims/unix/env.rs | 21 +++ src/tools/miri/src/shims/windows/env.rs | 9 +- 6 files changed, 137 insertions(+), 138 deletions(-) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 293b937a5e52b..3a282e89312a2 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -37,21 +37,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "annotate-snippets" version = "0.9.2" @@ -121,12 +106,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - [[package]] name = "camino" version = "1.1.6" @@ -177,10 +156,29 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "android-tzdata", - "iana-time-zone", "num-traits", - "windows-targets 0.52.3", +] + +[[package]] +name = "chrono-tz" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", ] [[package]] @@ -249,12 +247,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - [[package]] name = "cpufeatures" version = "0.2.12" @@ -379,29 +371,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "indenter" version = "0.3.3" @@ -455,15 +424,6 @@ dependencies = [ "libc", ] -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -587,6 +547,7 @@ version = "0.1.0" dependencies = [ "aes", "chrono", + "chrono-tz", "colored", "ctrlc", "directories", @@ -690,6 +651,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "perf-event-open-sys" version = "3.0.0" @@ -699,6 +669,44 @@ dependencies = [ "libc", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -931,6 +939,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "smallvec" version = "1.13.1" @@ -1094,60 +1108,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - [[package]] name = "winapi" version = "0.3.9" @@ -1170,15 +1130,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.3", -] - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index b00dae784d22c..de7a6de9e3e46 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -24,7 +24,8 @@ smallvec = "1.7" aes = { version = "0.8.3", features = ["hazmat"] } measureme = "11" ctrlc = "3.2.5" -chrono = { version = "0.4.38", default-features = false, features = ["clock"] } +chrono = { version = "0.4.38", default-features = false } +chrono-tz = "0.9" directories = "5" # Copied from `compiler/rustc/Cargo.toml`. diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index fc0160fdf2117..395a1ca62c612 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -1,4 +1,4 @@ -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use rustc_data_structures::fx::FxHashMap; @@ -99,4 +99,15 @@ impl<'tcx> EnvVars<'tcx> { } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Try to get an environment variable from the interpreted program's environment. This is + /// useful for implementing shims which are documented to read from the environment. + fn get_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { + let this = self.eval_context_ref(); + match &this.machine.env_vars { + EnvVars::Uninit => return Ok(None), + EnvVars::Unix(vars) => vars.get(this, name), + EnvVars::Windows(vars) => vars.get(name), + } + } +} diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index dfdf58470d63a..05dbdef1ba188 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -1,8 +1,10 @@ -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fmt::Write; +use std::str::FromStr; use std::time::{Duration, SystemTime}; -use chrono::{DateTime, Datelike, Local, Timelike, Utc}; +use chrono::{DateTime, Datelike, Offset, Timelike, Utc}; +use chrono_tz::Tz; use crate::concurrency::thread::MachineCallback; use crate::*; @@ -136,8 +138,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .unwrap(); let dt_utc: DateTime = DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp"); + + // Figure out what time zone is in use + let tz = this.get_var(OsStr::new("TZ"))?.unwrap_or_else(|| OsString::from("UTC")); + let tz = match tz.into_string() { + Ok(tz) => Tz::from_str(&tz).unwrap_or(Tz::UTC), + _ => Tz::UTC, + }; + // Convert that to local time, then return the broken-down time value. - let dt: DateTime = DateTime::from(dt_utc); + let dt: DateTime = dt_utc.with_timezone(&tz); // This value is always set to -1, because there is no way to know if dst is in effect with // chrono crate yet. @@ -146,17 +156,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // 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_second = Local::now().offset().local_minus_utc(); - let tm_gmtoff = offset_in_second; + let offset_in_seconds = dt.offset().fix().local_minus_utc(); + let tm_gmtoff = offset_in_seconds; let mut tm_zone = String::new(); - if offset_in_second < 0 { + if offset_in_seconds < 0 { tm_zone.push('-'); } else { tm_zone.push('+'); } - let offset_hour = offset_in_second.abs() / 3600; + let offset_hour = offset_in_seconds.abs() / 3600; write!(tm_zone, "{:02}", offset_hour).unwrap(); - let offset_min = (offset_in_second.abs() % 3600) / 60; + let offset_min = (offset_in_seconds.abs() % 3600) / 60; if offset_min != 0 { write!(tm_zone, "{:02}", offset_min).unwrap(); } diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 128f0dcafa942..f61a81b07cbbb 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -70,6 +70,27 @@ impl<'tcx> UnixEnvVars<'tcx> { pub(crate) fn environ(&self) -> Pointer> { self.environ.ptr() } + + /// Implementation detail for [`InterpCx::get_var`]. This basically does `getenv`, complete + /// with the reads of the environment, but returns an [`OsString`] instead of a pointer. + pub(crate) fn get<'mir>( + &self, + ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + name: &OsStr, + ) -> InterpResult<'tcx, Option> { + // We don't care about the value as we have the `map` to keep track of everything, + // but we do want to do this read so it shows up as a data race. + let _vars_ptr = ecx.read_pointer(&self.environ)?; + let Some(var_ptr) = self.map.get(name) else { + return Ok(None); + }; + // The offset is used to strip the "{name}=" part of the string. + let var_ptr = var_ptr.offset( + Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), + ecx, + )?; + ecx.read_os_str_from_c_str(var_ptr).map(|s| Some(s.to_owned())) + } } fn alloc_env_var<'mir, 'tcx>( diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index e91623ac87160..a8b0a77b23b74 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; @@ -9,7 +9,7 @@ use helpers::windows_check_buffer_size; #[derive(Default)] pub struct WindowsEnvVars { - /// Stores the environment varialbles. + /// Stores the environment variables. map: FxHashMap, } @@ -26,6 +26,11 @@ impl WindowsEnvVars { ) -> InterpResult<'tcx, Self> { Ok(Self { map: env_vars }) } + + /// Implementation detail for [`InterpCx::get_var`]. + pub(crate) fn get<'tcx>(&self, name: &OsStr) -> InterpResult<'tcx, Option> { + Ok(self.map.get(name).cloned()) + } } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} From 9bed19edc42fe7db30df8258d13598bfe7b1971b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 28 Apr 2024 17:45:08 -0400 Subject: [PATCH 11/47] Refactor UnixEnvVars::get so that it can be reused by getenv --- src/tools/miri/src/shims/env.rs | 12 ++++++++++-- src/tools/miri/src/shims/time.rs | 2 +- src/tools/miri/src/shims/unix/env.rs | 21 +++++---------------- src/tools/miri/src/shims/windows/env.rs | 2 +- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 395a1ca62c612..b95abb484c875 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -102,11 +102,19 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Try to get an environment variable from the interpreted program's environment. This is /// useful for implementing shims which are documented to read from the environment. - fn get_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { + fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); match &this.machine.env_vars { EnvVars::Uninit => return Ok(None), - EnvVars::Unix(vars) => vars.get(this, name), + EnvVars::Unix(vars) => { + let var_ptr = vars.get(this, name)?; + if let Some(ptr) = var_ptr { + let var = this.read_os_str_from_c_str(ptr)?; + Ok(Some(var.to_owned())) + } else { + Ok(None) + } + } EnvVars::Windows(vars) => vars.get(name), } } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 05dbdef1ba188..8d1f07f916c9b 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp"); // Figure out what time zone is in use - let tz = this.get_var(OsStr::new("TZ"))?.unwrap_or_else(|| OsString::from("UTC")); + let tz = this.get_env_var(OsStr::new("TZ"))?.unwrap_or_else(|| OsString::from("UTC")); let tz = match tz.into_string() { Ok(tz) => Tz::from_str(&tz).unwrap_or(Tz::UTC), _ => Tz::UTC, diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index f61a81b07cbbb..910e53260bfbc 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -71,13 +71,13 @@ impl<'tcx> UnixEnvVars<'tcx> { self.environ.ptr() } - /// Implementation detail for [`InterpCx::get_var`]. This basically does `getenv`, complete + /// Implementation detail for [`InterpCx::get_env_var`]. This basically does `getenv`, complete /// with the reads of the environment, but returns an [`OsString`] instead of a pointer. pub(crate) fn get<'mir>( &self, ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, name: &OsStr, - ) -> InterpResult<'tcx, Option> { + ) -> InterpResult<'tcx, Option>>> { // We don't care about the value as we have the `map` to keep track of everything, // but we do want to do this read so it shows up as a data race. let _vars_ptr = ecx.read_pointer(&self.environ)?; @@ -89,7 +89,7 @@ impl<'tcx> UnixEnvVars<'tcx> { Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), ecx, )?; - ecx.read_os_str_from_c_str(var_ptr).map(|s| Some(s.to_owned())) + Ok(Some(var_ptr)) } } @@ -137,19 +137,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; - // We don't care about the value as we have the `map` to keep track of everything, - // but we do want to do this read so it shows up as a data race. - let _vars_ptr = this.read_pointer(&this.machine.env_vars.unix().environ)?; - Ok(match this.machine.env_vars.unix().map.get(name) { - Some(var_ptr) => { - // The offset is used to strip the "{name}=" part of the string. - var_ptr.offset( - Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), - this, - )? - } - None => Pointer::null(), - }) + let var_ptr = this.machine.env_vars.unix().get(this, name)?; + Ok(var_ptr.unwrap_or_else(Pointer::null)) } fn setenv( diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index a8b0a77b23b74..b3bc5d4d85235 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -27,7 +27,7 @@ impl WindowsEnvVars { Ok(Self { map: env_vars }) } - /// Implementation detail for [`InterpCx::get_var`]. + /// Implementation detail for [`InterpCx::get_env_var`]. pub(crate) fn get<'tcx>(&self, name: &OsStr) -> InterpResult<'tcx, Option> { Ok(self.map.get(name).cloned()) } From 7afef08b6d01c4baabe4523f4b91ea2d1748f0e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Apr 2024 17:33:35 +0200 Subject: [PATCH 12/47] don't leak UnixEnvVars impl details into get_env_var --- src/tools/miri/src/shims/env.rs | 10 +--------- src/tools/miri/src/shims/unix/env.rs | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index b95abb484c875..695d1138756ca 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -106,15 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_ref(); match &this.machine.env_vars { EnvVars::Uninit => return Ok(None), - EnvVars::Unix(vars) => { - let var_ptr = vars.get(this, name)?; - if let Some(ptr) = var_ptr { - let var = this.read_os_str_from_c_str(ptr)?; - Ok(Some(var.to_owned())) - } else { - Ok(None) - } - } + EnvVars::Unix(vars) => vars.get(this, name), EnvVars::Windows(vars) => vars.get(name), } } diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 910e53260bfbc..9082d13da8404 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -71,9 +71,7 @@ impl<'tcx> UnixEnvVars<'tcx> { self.environ.ptr() } - /// Implementation detail for [`InterpCx::get_env_var`]. This basically does `getenv`, complete - /// with the reads of the environment, but returns an [`OsString`] instead of a pointer. - pub(crate) fn get<'mir>( + fn get_ptr<'mir>( &self, ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, name: &OsStr, @@ -91,6 +89,22 @@ impl<'tcx> UnixEnvVars<'tcx> { )?; Ok(Some(var_ptr)) } + + /// Implementation detail for [`InterpCx::get_env_var`]. This basically does `getenv`, complete + /// with the reads of the environment, but returns an [`OsString`] instead of a pointer. + pub(crate) fn get<'mir>( + &self, + ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + name: &OsStr, + ) -> InterpResult<'tcx, Option> { + let var_ptr = self.get_ptr(ecx, name)?; + if let Some(ptr) = var_ptr { + let var = ecx.read_os_str_from_c_str(ptr)?; + Ok(Some(var.to_owned())) + } else { + Ok(None) + } + } } fn alloc_env_var<'mir, 'tcx>( @@ -137,7 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; - let var_ptr = this.machine.env_vars.unix().get(this, name)?; + let var_ptr = this.machine.env_vars.unix().get_ptr(this, name)?; Ok(var_ptr.unwrap_or_else(Pointer::null)) } From 1cf951e5c6efd4fa55031b72f17c196e74b0f349 Mon Sep 17 00:00:00 2001 From: Paul Gey Date: Wed, 1 May 2024 21:27:49 +0200 Subject: [PATCH 13/47] =?UTF-8?q?Don=E2=80=99t=20print=20`Preparing=20a=20?= =?UTF-8?q?sysroot`=20when=20`-q`/`--quiet`=20is=20passed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/miri/cargo-miri/src/phases.rs | 3 ++- src/tools/miri/cargo-miri/src/setup.rs | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index b774ca8fa7252..6a3b6f68a7ed3 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -87,6 +87,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { ), }; let verbose = num_arg_flag("-v"); + let quiet = has_arg_flag("-q") || has_arg_flag("--quiet"); // Determine the involved architectures. let rustc_version = VersionMeta::for_command(miri_for_host()).unwrap_or_else(|err| { @@ -110,7 +111,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { } // We always setup. - let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose); + let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose, quiet); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index 401e9158faec5..9a58e6fa018da 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -19,6 +19,7 @@ pub fn setup( target: &str, rustc_version: &VersionMeta, verbose: usize, + quiet: bool, ) -> PathBuf { let only_setup = matches!(subcommand, MiriCommand::Setup); let ask_user = !only_setup; @@ -119,6 +120,9 @@ pub fn setup( for _ in 0..verbose { command.arg("-v"); } + if quiet { + command.arg("--quiet"); + } } else { // Suppress output. command.stdout(process::Stdio::null()); @@ -134,7 +138,7 @@ pub fn setup( let rustflags = &["-Cdebug-assertions=off", "-Coverflow-checks=on"]; // Do the build. - if print_sysroot { + if print_sysroot || quiet { // Be silent. } else { let mut msg = String::new(); @@ -169,7 +173,7 @@ pub fn setup( ) } }); - if print_sysroot { + if print_sysroot || quiet { // Be silent. } else if only_setup { eprintln!("A sysroot for Miri is now available in `{}`.", sysroot_dir.display()); From 4b4262691da5fe93e3226842efbdd06f89e1abb3 Mon Sep 17 00:00:00 2001 From: Paul Gey Date: Wed, 1 May 2024 21:34:50 +0200 Subject: [PATCH 14/47] fix usage example for `--print-sysroot` --- src/tools/miri/cargo-miri/src/phases.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 6a3b6f68a7ed3..e2fc2a0c2779b 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -28,7 +28,7 @@ Examples: cargo miri run cargo miri test -- test-suite-filter - cargo miri setup --print sysroot + cargo miri setup --print-sysroot This will print the path to the generated sysroot (and nothing else) on stdout. stderr will still contain progress information about how the build is doing. From a2b3211b199375f358ec087e8a264063417e2d22 Mon Sep 17 00:00:00 2001 From: Paul Gey Date: Wed, 1 May 2024 21:50:45 +0200 Subject: [PATCH 15/47] no longer strip `Preparing a sysroot` message from test output --- src/tools/miri/test-cargo-miri/run-test.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index cac11dff77557..2639d29b73de6 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -34,10 +34,6 @@ def normalize_stdout(str): str = re.sub("finished in \\d+\\.\\d\\ds", "finished in $TIME", str) # the time keeps changing, obviously return str -def normalize_stderr(str): - str = re.sub("Preparing a sysroot for Miri \\(target: [a-z0-9_-]+\\)\\.\\.\\. done\n", "", str) # remove leading cargo-miri setup output - return str - def check_output(actual, path, name): if os.environ.get("RUSTC_BLESS", "0") != "0": # Write the output only if bless is set @@ -69,7 +65,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env=None): ) (stdout, stderr) = p.communicate(input=stdin) stdout = normalize_stdout(stdout.decode("UTF-8")) - stderr = normalize_stderr(stderr.decode("UTF-8")) + stderr = stderr.decode("UTF-8") stdout_matches = check_output(stdout, stdout_ref, "stdout") stderr_matches = check_output(stderr, stderr_ref, "stderr") From aa986f080080e293d059255baee26638728eaee7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 May 2024 11:09:01 +0200 Subject: [PATCH 16/47] Tree Borrows: first apply transition, then check protector with new 'initialized' --- src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 2470624181e74..ff4589657aff2 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -106,6 +106,8 @@ impl LocationState { let old_perm = self.permission; let transition = Permission::perform_access(access_kind, rel_pos, old_perm, protected) .ok_or(TransitionError::ChildAccessForbidden(old_perm))?; + self.initialized |= !rel_pos.is_foreign(); + self.permission = transition.applied(old_perm).unwrap(); // Why do only initialized locations cause protector errors? // Consider two mutable references `x`, `y` into disjoint parts of // the same allocation. A priori, these may actually both be used to @@ -123,8 +125,6 @@ impl LocationState { if protected && self.initialized && transition.produces_disabled() { return Err(TransitionError::ProtectedDisabled(old_perm)); } - self.permission = transition.applied(old_perm).unwrap(); - self.initialized |= !rel_pos.is_foreign(); Ok(transition) } From 36caaa9f4f10547903a8bd15f435d02bc48c1ce6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 May 2024 19:13:28 +0200 Subject: [PATCH 17/47] update host-float comments --- src/tools/miri/src/shims/foreign_items.rs | 12 ++++++------ src/tools/miri/src/shims/intrinsics/mod.rs | 16 ++++++++-------- src/tools/miri/src/shims/intrinsics/simd.rs | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 636361148a469..4b96ff18b74cb 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -730,7 +730,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let f = this.read_scalar(f)?.to_f32()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); let res = match link_name.as_str() { "cbrtf" => f_host.cbrt(), @@ -761,7 +761,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let f2 = this.read_scalar(f2)?.to_f32()?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let res = match link_name.as_str() { "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(), "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(), @@ -787,7 +787,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let f = this.read_scalar(f)?.to_f64()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); let res = match link_name.as_str() { "cbrt" => f_host.cbrt(), @@ -818,7 +818,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let f2 = this.read_scalar(f2)?.to_f64()?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let res = match link_name.as_str() { "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(), "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(), @@ -848,7 +848,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let x = this.read_scalar(x)?.to_f32()?; let signp = this.deref_pointer(signp)?; - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); this.write_int(sign, &signp)?; let res = this.adjust_nan(res.to_soft(), &[x]); @@ -859,7 +859,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let x = this.read_scalar(x)?.to_f64()?; let signp = this.deref_pointer(signp)?; - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); this.write_int(sign, &signp)?; let res = this.adjust_nan(res.to_soft(), &[x]); diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index d16d5d99e9c01..a7ba4fd7f9e54 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -193,12 +193,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); let res = match intrinsic_name { "sinf32" => f_host.sin(), "cosf32" => f_host.cos(), - "sqrtf32" => f_host.sqrt(), + "sqrtf32" => f_host.sqrt(), // FIXME Using host floats, this should use full-precision soft-floats "expf32" => f_host.exp(), "exp2f32" => f_host.exp2(), "logf32" => f_host.ln(), @@ -238,12 +238,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); let res = match intrinsic_name { "sinf64" => f_host.sin(), "cosf64" => f_host.cos(), - "sqrtf64" => f_host.sqrt(), + "sqrtf64" => f_host.sqrt(), // FIXME Using host floats, this should use full-precision soft-floats "expf64" => f_host.exp(), "exp2f64" => f_host.exp2(), "logf64" => f_host.ln(), @@ -366,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [f1, f2] = check_arg_count(args)?; let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f1.to_host().powf(f2.to_host()).to_soft(); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; @@ -376,7 +376,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [f1, f2] = check_arg_count(args)?; let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f1.to_host().powf(f2.to_host()).to_soft(); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; @@ -386,7 +386,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [f, i] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; let i = this.read_scalar(i)?.to_i32()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f.to_host().powi(i).to_soft(); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; @@ -396,7 +396,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [f, i] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; let i = this.read_scalar(i)?.to_i32()?; - // FIXME: Using host floats. + // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f.to_host().powi(i).to_soft(); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 9a0671430d438..e6d6f72404e11 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -99,14 +99,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let ty::Float(float_ty) = op.layout.ty.kind() else { span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; - // FIXME using host floats + // Using host floats (but it's fine, these operations do not have guaranteed precision). match float_ty { FloatTy::F16 => unimplemented!("f16_f128"), FloatTy::F32 => { let f = op.to_scalar().to_f32()?; let f_host = f.to_host(); let res = match host_op { - "fsqrt" => f_host.sqrt(), + "fsqrt" => f_host.sqrt(), // FIXME Using host floats, this should use full-precision soft-floats "fsin" => f_host.sin(), "fcos" => f_host.cos(), "fexp" => f_host.exp(), From 56bb51761ab90fa3ccc6261d59b71d2fdc404b54 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 3 May 2024 07:05:29 +0800 Subject: [PATCH 18/47] Add assign --- src/tools/miri/triagebot.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index 3b767b3e62f13..22dc0c49aa815 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -10,5 +10,14 @@ allow-unauthenticated = [ # Gives us the commands 'ready', 'author', 'blocked' [shortcut] +# Gives us 'claim', 'release-assignment', 'assign @user' +[assign] +# If set, posts a warning message if the PR is opened against a non-default +# branch (usually main or master). +warn_non_default_branch = true +# If set, the welcome message to new contributors will include this link to +# a contributing guide. +contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html" + [no-merges] exclude_titles = ["Rustup"] From aeef18043eba235bb4bc74f169ee92ffaa3024db Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 3 May 2024 04:56:14 +0000 Subject: [PATCH 19/47] 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 a45ecda15c4c0..dcd7b0698a6b3 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -6acb9e75ebc936df737381a9d0b7a7bccd6f0b2f +79734f1db8dbe322192dea32c0f6b80ab14c4c1d From b348e418611dd38b9022e0dc95d125daf64c2492 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 May 2024 08:00:24 +0200 Subject: [PATCH 20/47] update comments and URL --- src/tools/miri/triagebot.toml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index 22dc0c49aa815..addb36418d4b4 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -10,14 +10,10 @@ allow-unauthenticated = [ # Gives us the commands 'ready', 'author', 'blocked' [shortcut] -# Gives us 'claim', 'release-assignment', 'assign @user' +# Enables assigning users to issues and PRs. [assign] -# If set, posts a warning message if the PR is opened against a non-default -# branch (usually main or master). warn_non_default_branch = true -# If set, the welcome message to new contributors will include this link to -# a contributing guide. -contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html" +contributing_url = "https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md" [no-merges] exclude_titles = ["Rustup"] From cde5f68948e5bf0934915673b50d6ca5b048a28a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 May 2024 08:10:16 +0200 Subject: [PATCH 21/47] update lockfile --- src/tools/miri/Cargo.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 3a282e89312a2..6960c1661c5e8 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -553,7 +553,6 @@ dependencies = [ "directories", "getrandom", "jemalloc-sys", - "lazy_static", "libc", "libffi", "libloading", From 413bac57c7ea87293dc2ec714ffbedecbaceb1d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 May 2024 19:36:33 +0200 Subject: [PATCH 22/47] run clippy on a Windows host --- src/tools/miri/.github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 3f714fc93201a..3d7ec210dac58 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -78,6 +78,12 @@ jobs: rustc -Vv cargo -V + # The `style` job only runs on Linux; this makes sure the Windows-host-specific + # code is also covered by clippy. + - name: Check clippy + if: ${{ matrix.os == 'windows-latest' }} + run: ./miri clippy -- -D warnings + - name: Test Miri run: ./ci/ci.sh From 01bfef9dc8cee75e078e55d3f080a26291d47daf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 May 2024 19:52:08 +0200 Subject: [PATCH 23/47] 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 dcd7b0698a6b3..b2e6353778f5a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -79734f1db8dbe322192dea32c0f6b80ab14c4c1d +d6d3b342e85272f5e75c0d7a1dd3a1d8becb40ac From 803201af66e6b20bee2c1a03d73ab7df9da36ec3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 May 2024 20:31:27 +0200 Subject: [PATCH 24/47] ./miri run: support -v flag to print what it is doing --- src/tools/miri/miri-script/src/commands.rs | 21 ++++++++------ src/tools/miri/miri-script/src/main.rs | 32 ++++++++++++---------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 575bf4a15dfd0..b460c7eba5601 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -162,7 +162,7 @@ impl Command { Command::Build { flags } => Self::build(flags), Command::Check { flags } => Self::check(flags), Command::Test { bless, flags } => Self::test(bless, flags), - Command::Run { dep, flags } => Self::run(dep, flags), + Command::Run { dep, verbose, flags } => Self::run(dep, verbose, flags), Command::Fmt { flags } => Self::fmt(flags), Command::Clippy { flags } => Self::clippy(flags), Command::Cargo { flags } => Self::cargo(flags), @@ -495,7 +495,7 @@ impl Command { Ok(()) } - fn run(dep: bool, mut flags: Vec) -> Result<()> { + fn run(dep: bool, verbose: bool, mut flags: Vec) -> Result<()> { let mut e = MiriEnv::new()?; // Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so // that we set the MIRI_SYSROOT up the right way. We must make sure that @@ -522,7 +522,7 @@ impl Command { } // Prepare a sysroot, and add it to the flags. - let miri_sysroot = e.build_miri_sysroot(/* quiet */ true)?; + let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose)?; flags.push("--sysroot".into()); flags.push(miri_sysroot.into()); @@ -532,17 +532,20 @@ impl Command { let miri_flags = flagsplit(&miri_flags); let toolchain = &e.toolchain; let extra_flags = &e.cargo_extra_flags; - if dep { + let quiet_flag = if verbose { None } else { Some("--quiet") }; + let mut cmd = if dep { cmd!( e.sh, - "cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {flags...}" - ).quiet().run()?; + "cargo +{toolchain} {quiet_flag...} test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {flags...}" + ) } else { cmd!( e.sh, - "cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}" - ).quiet().run()?; - } + "cargo +{toolchain} {quiet_flag...} run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}" + ) + }; + cmd.set_quiet(!verbose); + cmd.run()?; Ok(()) } diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 712180be2825a..4904744cb9f6b 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -38,6 +38,7 @@ pub enum Command { /// (Also respects MIRIFLAGS environment variable.) Run { dep: bool, + verbose: bool, /// Flags that are passed through to `miri`. flags: Vec, }, @@ -90,7 +91,7 @@ Just check miri. are passed to `cargo check`. Build miri, set up a sysroot and then run the test suite. are passed to the final `cargo test` invocation. -./miri run [--dep] : +./miri run [--dep] [-v|--verbose] : Build miri, set up a sysroot and then run the driver with the given . (Also respects MIRIFLAGS environment variable.) @@ -132,10 +133,10 @@ 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 : +./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. +clone of the rustc repo. The branch defaults to `miri-sync`. ENVIRONMENT VARIABLES @@ -162,12 +163,18 @@ fn main() -> Result<()> { Command::Test { bless, flags: args.collect() } } Some("run") => { - let dep = args.peek().is_some_and(|a| a.to_str() == Some("--dep")); - if dep { - // Consume the flag. + let mut dep = false; + let mut verbose = false; + while let Some(arg) = args.peek().and_then(|a| a.to_str()) { + match arg { + "--dep" => dep = true, + "-v" | "--verbose" => verbose = true, + _ => break, // not for us + } + // Consume the flag, look at the next one. args.next().unwrap(); } - Command::Run { dep, flags: args.collect() } + Command::Run { dep, verbose, flags: args.collect() } } Some("fmt") => Command::Fmt { flags: args.collect() }, Some("clippy") => Command::Clippy { flags: args.collect() }, @@ -187,17 +194,12 @@ fn main() -> Result<()> { let github_user = args .next() .ok_or_else(|| { - anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER BRANCH`") - })? - .to_string_lossy() - .into_owned(); - let branch = args - .next() - .ok_or_else(|| { - anyhow!("Missing second argument for `./miri rustc-push GITHUB_USER BRANCH`") + anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER [BRANCH]`") })? .to_string_lossy() .into_owned(); + let branch = + args.next().unwrap_or_else(|| "miri-sync".into()).to_string_lossy().into_owned(); if args.next().is_some() { bail!("Too many arguments for `./miri rustc-push GITHUB_USER BRANCH`"); } From 4dd8e0b3bc1c7876b623b1381a81d9f055a566de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 May 2024 21:45:03 +0200 Subject: [PATCH 25/47] CI: no need to surround if: condition in expansion braces --- src/tools/miri/.github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 3d7ec210dac58..3bc4163ab5246 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -61,7 +61,7 @@ jobs: restore-keys: cargo-${{ runner.os }}-reset20240425 - name: Install tools - if: ${{ steps.cache.outputs.cache-hit != 'true' }} + if: steps.cache.outputs.cache-hit != 'true' run: cargo install -f rustup-toolchain-install-master hyperfine - name: Install miri toolchain @@ -81,7 +81,7 @@ jobs: # The `style` job only runs on Linux; this makes sure the Windows-host-specific # code is also covered by clippy. - name: Check clippy - if: ${{ matrix.os == 'windows-latest' }} + if: matrix.os == 'windows-latest' run: ./miri clippy -- -D warnings - name: Test Miri @@ -117,7 +117,7 @@ jobs: restore-keys: cargo-${{ runner.os }}-reset20240331 - name: Install rustup-toolchain-install-master - if: ${{ steps.cache.outputs.cache-hit != 'true' }} + if: steps.cache.outputs.cache-hit != 'true' run: cargo install -f rustup-toolchain-install-master - name: Install "master" toolchain From 39ddcc6f8551f9157812a7677f8c99dc61275629 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 00:03:23 +0200 Subject: [PATCH 26/47] make many-seeds a mode of ./miri run rather than a separate command --- src/tools/miri/ci/ci.sh | 13 ++- src/tools/miri/miri-script/Cargo.lock | 8 +- src/tools/miri/miri-script/Cargo.toml | 2 +- src/tools/miri/miri-script/src/commands.rs | 96 ++++++++++------------ src/tools/miri/miri-script/src/main.rs | 49 ++++++----- src/tools/miri/miri-script/src/util.rs | 53 ++++++++++++ 6 files changed, 134 insertions(+), 87 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index c1ffb80783ef6..0db267650dbf6 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -71,10 +71,9 @@ function run_tests { time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} fi if [ -n "${MANY_SEEDS-}" ]; then - # Also run some many-seeds tests. 64 seeds means this takes around a minute per test. - # (Need to invoke via explicit `bash -c` for Windows.) + # Also run some many-seeds tests. time for FILE in tests/many-seeds/*.rs; do - MIRI_SEEDS=$MANY_SEEDS ./miri many-seeds "$BASH" -c "./miri run '$FILE'" + ./miri run "--many-seeds=0..$MANY_SEEDS" "$FILE" done fi if [ -n "${TEST_BENCH-}" ]; then @@ -135,7 +134,7 @@ case $HOST_TARGET in GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 # With reduced many-seed count to avoid spending too much time on that. - # (All OSes are run with 64 seeds at least once though via the macOS runner.) + # (All OSes and ABIs are run with 64 seeds at least once though via the macOS runner.) MANY_SEEDS=16 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests @@ -164,9 +163,9 @@ case $HOST_TARGET in ;; i686-pc-windows-msvc) # Host - # Only smoke-test `many-seeds`; 64 runs of just the scoped-thread-leak test take 15min here! - # See . - GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=1 TEST_BENCH=1 run_tests + # With reduced many-seeds count as this is the slowest runner already. + # (The macOS runner checks windows-msvc with full many-seeds count.) + GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=16 TEST_BENCH=1 run_tests # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, # and a 64bit target works on a 32bit host. diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index a6f7467f0a2f7..5e792abac175d 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -466,15 +466,15 @@ checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" [[package]] name = "xshell" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" dependencies = [ "xshell-macros", ] [[package]] name = "xshell-macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 79d0b13600d4f..631d3a82102b5 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -19,7 +19,7 @@ itertools = "0.11" path_macro = "1.0" shell-words = "1.1" anyhow = "1.0" -xshell = "0.2" +xshell = "0.2.6" rustc_version = "0.4" dunce = "1.0.4" directories = "5" diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index b460c7eba5601..7e34ad050b319 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -2,6 +2,7 @@ use std::env; use std::ffi::OsString; use std::io::Write; use std::ops::Not; +use std::ops::Range; use std::path::PathBuf; use std::process; use std::thread; @@ -150,7 +151,6 @@ impl Command { | Command::Fmt { .. } | Command::Clippy { .. } | Command::Cargo { .. } => Self::auto_actions()?, - | Command::ManySeeds { .. } | Command::Toolchain { .. } | Command::Bench { .. } | Command::RustcPull { .. } @@ -162,11 +162,11 @@ impl Command { Command::Build { flags } => Self::build(flags), Command::Check { flags } => Self::check(flags), Command::Test { bless, flags } => Self::test(bless, flags), - Command::Run { dep, verbose, flags } => Self::run(dep, verbose, flags), + Command::Run { dep, verbose, many_seeds, flags } => + Self::run(dep, verbose, many_seeds, flags), Command::Fmt { flags } => Self::fmt(flags), Command::Clippy { flags } => Self::clippy(flags), Command::Cargo { flags } => Self::cargo(flags), - Command::ManySeeds { command } => Self::many_seeds(command), Command::Bench { benches } => Self::bench(benches), Command::Toolchain { flags } => Self::toolchain(flags), Command::RustcPull { commit } => Self::rustc_pull(commit.clone()), @@ -367,43 +367,6 @@ impl Command { Ok(()) } - fn many_seeds(command: Vec) -> Result<()> { - let seed_start: u64 = env::var("MIRI_SEED_START") - .unwrap_or_else(|_| "0".into()) - .parse() - .context("failed to parse MIRI_SEED_START")?; - let seed_end: u64 = match (env::var("MIRI_SEEDS"), env::var("MIRI_SEED_END")) { - (Ok(_), Ok(_)) => bail!("Only one of MIRI_SEEDS and MIRI_SEED_END may be set"), - (Ok(seeds), Err(_)) => - seed_start + seeds.parse::().context("failed to parse MIRI_SEEDS")?, - (Err(_), Ok(seed_end)) => seed_end.parse().context("failed to parse MIRI_SEED_END")?, - (Err(_), Err(_)) => seed_start + 256, - }; - if seed_end <= seed_start { - bail!("the end of the seed range must be larger than the start."); - } - - let Some((command_name, trailing_args)) = command.split_first() else { - bail!("expected many-seeds command to be non-empty"); - }; - let sh = Shell::new()?; - sh.set_var("MIRI_AUTO_OPS", "no"); // just in case we get recursively invoked - for seed in seed_start..seed_end { - println!("Trying seed: {seed}"); - let mut miriflags = env::var_os("MIRIFLAGS").unwrap_or_default(); - miriflags.push(format!(" -Zlayout-seed={seed} -Zmiri-seed={seed}")); - let status = cmd!(sh, "{command_name} {trailing_args...}") - .env("MIRIFLAGS", miriflags) - .quiet() - .run(); - if let Err(err) = status { - println!("Failing seed: {seed}"); - return Err(err.into()); - } - } - Ok(()) - } - fn bench(benches: Vec) -> Result<()> { // The hyperfine to use let hyperfine = env::var("HYPERFINE"); @@ -495,7 +458,12 @@ impl Command { Ok(()) } - fn run(dep: bool, verbose: bool, mut flags: Vec) -> Result<()> { + fn run( + dep: bool, + verbose: bool, + many_seeds: Option>, + mut flags: Vec, + ) -> Result<()> { let mut e = MiriEnv::new()?; // Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so // that we set the MIRI_SYSROOT up the right way. We must make sure that @@ -526,26 +494,46 @@ impl Command { flags.push("--sysroot".into()); flags.push(miri_sysroot.into()); - // Then run the actual command. Also add MIRIFLAGS. + // Compute everything needed to run the actual command. Also add MIRIFLAGS. let miri_manifest = path!(e.miri_dir / "Cargo.toml"); let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default(); let miri_flags = flagsplit(&miri_flags); let toolchain = &e.toolchain; let extra_flags = &e.cargo_extra_flags; let quiet_flag = if verbose { None } else { Some("--quiet") }; - let mut cmd = if dep { - cmd!( - e.sh, - "cargo +{toolchain} {quiet_flag...} test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {flags...}" - ) - } else { - cmd!( - e.sh, - "cargo +{toolchain} {quiet_flag...} run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}" - ) + // This closure runs the command with the given `seed_flag` added between the MIRIFLAGS and + // the `flags` given on the command-line. + let run_miri = |sh: &Shell, seed_flag: Option| -> Result<()> { + // The basic command that executes the Miri driver. + let mut cmd = if dep { + cmd!( + sh, + "cargo +{toolchain} {quiet_flag...} test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode" + ) + } else { + cmd!( + sh, + "cargo +{toolchain} {quiet_flag...} run {extra_flags...} --manifest-path {miri_manifest} --" + ) + }; + cmd.set_quiet(!verbose); + // Add Miri flags + let cmd = cmd.args(&miri_flags).args(seed_flag).args(&flags); + // And run the thing. + Ok(cmd.run()?) }; - cmd.set_quiet(!verbose); - cmd.run()?; + // Run the closure once or many times. + if let Some(seed_range) = many_seeds { + e.run_many_times(seed_range, |sh, seed| { + eprintln!("Trying seed: {seed}"); + run_miri(sh, Some(format!("-Zmiri-seed={seed}"))).map_err(|err| { + eprintln!("FAILING SEED: {seed}"); + err + }) + })?; + } else { + run_miri(&e.sh, None)?; + } Ok(()) } diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 4904744cb9f6b..f0ebbc846906e 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -3,10 +3,10 @@ mod commands; mod util; -use std::env; use std::ffi::OsString; +use std::{env, ops::Range}; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, bail, Context, Result}; #[derive(Clone, Debug)] pub enum Command { @@ -39,6 +39,7 @@ pub enum Command { Run { dep: bool, verbose: bool, + many_seeds: Option>, /// Flags that are passed through to `miri`. flags: Vec, }, @@ -55,10 +56,6 @@ pub enum Command { /// Runs just `cargo ` with the Miri-specific environment variables. /// Mainly meant to be invoked by rust-analyzer. Cargo { flags: Vec }, - /// Runs over and over again with different seeds for Miri. The MIRIFLAGS - /// variable is set to its original value appended with ` -Zmiri-seed=$SEED` for - /// many different seeds. - ManySeeds { command: Vec }, /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. Bench { /// List of benchmarks to run. By default all benchmarks are run. @@ -91,9 +88,11 @@ Just check miri. are passed to `cargo check`. Build miri, set up a sysroot and then run the test suite. are passed to the final `cargo test` invocation. -./miri run [--dep] [-v|--verbose] : +./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..256`. ./miri fmt : Format all sources and tests. are passed to `rustfmt`. @@ -111,13 +110,6 @@ 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 many-seeds : -Runs over and over again with different seeds for Miri. The MIRIFLAGS -variable is set to its original value appended with ` -Zmiri-seed=$SEED` for -many different seeds. MIRI_SEED_START controls the first seed to try (default: 0). -MIRI_SEEDS controls how many seeds are being tried (default: 256); -alternatively, MIRI_SEED_END controls the end of the (exclusive) seed range to try. - ./miri bench : 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. @@ -165,22 +157,37 @@ fn main() -> Result<()> { Some("run") => { let mut dep = false; let mut verbose = false; - while let Some(arg) = args.peek().and_then(|a| a.to_str()) { - match arg { - "--dep" => dep = true, - "-v" | "--verbose" => verbose = true, - _ => break, // not for us + let mut many_seeds = None; + while let Some(arg) = args.peek().and_then(|s| s.to_str()) { + if arg == "--dep" { + dep = true; + } else if arg == "-v" || arg == "--verbose" { + verbose = true; + } else if arg == "--many-seeds" { + many_seeds = Some(0..256); + } else if let Some(val) = arg.strip_prefix("--many-seeds=") { + 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 { + break; // not for us } // Consume the flag, look at the next one. args.next().unwrap(); } - Command::Run { dep, verbose, flags: args.collect() } + Command::Run { dep, verbose, many_seeds, flags: args.collect() } } Some("fmt") => Command::Fmt { flags: args.collect() }, Some("clippy") => Command::Clippy { flags: args.collect() }, Some("cargo") => Command::Cargo { flags: args.collect() }, Some("install") => Command::Install { flags: args.collect() }, - Some("many-seeds") => Command::ManySeeds { command: args.collect() }, Some("bench") => Command::Bench { benches: args.collect() }, Some("toolchain") => Command::Toolchain { flags: args.collect() }, Some("rustc-pull") => { diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index 361a4ca0cf769..23b5e936edd81 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -1,5 +1,8 @@ use std::ffi::{OsStr, OsString}; +use std::ops::Range; use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use std::thread; use anyhow::{anyhow, Context, Result}; use dunce::canonicalize; @@ -189,4 +192,54 @@ impl MiriEnv { Ok(()) } + + /// Run the given closure many times in parallel with access to the shell, once for each value in the `range`. + pub fn run_many_times( + &self, + range: Range, + run: impl Fn(&Shell, u32) -> Result<()> + Sync, + ) -> Result<()> { + // `next` is atomic so threads can concurrently fetch their next value to run. + let next = AtomicU32::new(range.start); + let end = range.end; // exclusive! + let failed = AtomicBool::new(false); + thread::scope(|s| { + let mut handles = Vec::new(); + // Spawn one worker per core. + for _ in 0..thread::available_parallelism()?.get() { + // Create a copy of the shell for this thread. + let local_shell = self.sh.clone(); + let handle = s.spawn(|| -> Result<()> { + let local_shell = local_shell; // move the copy into this thread. + // Each worker thread keeps asking for numbers until we're all done. + loop { + let cur = next.fetch_add(1, Ordering::Relaxed); + if cur >= end { + // We hit the upper limit and are done. + break; + } + // Run the command with this seed. + run(&local_shell, cur).map_err(|err| { + // If we failed, tell everyone about this. + failed.store(true, Ordering::Relaxed); + err + })?; + // Check if some other command failed (in which case we'll stop as well). + if failed.load(Ordering::Relaxed) { + return Ok(()); + } + } + Ok(()) + }); + handles.push(handle); + } + // Wait for all workers to be done. + for handle in handles { + handle.join().unwrap()?; + } + // If all workers succeeded, we can't have failed. + assert!(!failed.load(Ordering::Relaxed)); + Ok(()) + }) + } } From 20fcbaaa100c876aad1ea14b51cc5b21484f3c4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 09:02:51 +0200 Subject: [PATCH 27/47] remove a hack that is no longer needed --- src/tools/miri/ci/ci.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 0db267650dbf6..c8c24ba5da61a 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -13,15 +13,6 @@ function endgroup { begingroup "Building Miri" -# Special Windows hacks -if [ "$HOST_TARGET" = i686-pc-windows-msvc ]; then - # The $BASH variable is `/bin/bash` here, but that path does not actually work. There are some - # hacks in place somewhere to try to paper over this, but the hacks dont work either (see - # ). So we hard-code the correct location for Github - # CI instead. - BASH="C:/Program Files/Git/usr/bin/bash" -fi - # Global configuration export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 From f1de4c16ee3dae0599efa64d6ebe601efbe23769 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 4 May 2024 00:54:21 -0700 Subject: [PATCH 28/47] Use `unchecked_sub` in `split_at` --- library/core/src/slice/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6e1ba74f72b33..6e6d66f0aae02 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -9,7 +9,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::fmt; use crate::hint; -use crate::intrinsics::exact_div; +use crate::intrinsics::{exact_div, unchecked_sub}; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{Bound, OneSidedRange, Range, RangeBounds}; @@ -1983,7 +1983,7 @@ impl [T] { ); // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) } + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), unchecked_sub(len, mid))) } } /// Divides one mutable slice into two at an index, without doing bounds checking. @@ -2035,7 +2035,12 @@ impl [T] { // // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // is fine. - unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } + unsafe { + ( + from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.add(mid), unchecked_sub(len, mid)), + ) + } } /// Divides one slice into two at an index, returning `None` if the slice is From 4082c247f50d63f0b2b40941fe55f2f5b1a9225e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 10:45:54 +0200 Subject: [PATCH 29/47] tls dtors: treat all unixes uniformly --- src/tools/miri/src/shims/tls.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index d25bae1cdc03f..0dec12f0b65f1 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -242,21 +242,21 @@ impl<'tcx> TlsDtorsState<'tcx> { match &mut self.0 { Init => { match this.tcx.sess.target.os.as_ref() { - "linux" | "freebsd" | "android" => { - // Run the pthread dtors. - break 'new_state PthreadDtors(Default::default()); - } "macos" => { // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. this.schedule_macos_tls_dtor()?; - // When the stack is empty again, go on with the pthread dtors. + // When that destructor is done, go on with the pthread dtors. + break 'new_state PthreadDtors(Default::default()); + } + _ if this.target_os_is_unix() => { + // All other Unixes directly jump to running the pthread dtors. break 'new_state PthreadDtors(Default::default()); } "windows" => { // Determine which destructors to run. let dtors = this.lookup_windows_tls_dtors()?; - // And move to the final state. + // And move to the next state, that runs them. break 'new_state WindowsDtors(dtors); } _ => { From 45670bf741654fd47dd448665fdb547ec40ec8b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 10:52:25 +0200 Subject: [PATCH 30/47] macos: use getentropy from libc --- src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs b/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs index 4b863f6851618..06109397c2bc6 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs @@ -1,12 +1,5 @@ //@ignore-target-windows: no libc -// on macOS this is not in the `libc` crate. -#[cfg(target_os = "macos")] -extern "C" { - fn getentropy(bytes: *mut libc::c_void, count: libc::size_t) -> libc::c_int; -} - -#[cfg(not(target_os = "macos"))] use libc::getentropy; fn main() { From 459c6ce944ccef19f5da60d8ee1fbdccf685e2b3 Mon Sep 17 00:00:00 2001 From: Luv-Ray Date: Sat, 4 May 2024 17:24:18 +0800 Subject: [PATCH 31/47] Make file descriptors into refcount references take ownership of self and return `io::Result<()>` in `FileDescription::close` Co-authored-by: Ralf Jung --- src/tools/miri/src/shims/unix/fd.rs | 172 +++++++++--------- src/tools/miri/src/shims/unix/fs.rs | 120 ++++++------ src/tools/miri/src/shims/unix/linux/epoll.rs | 69 ++++--- .../miri/src/shims/unix/linux/eventfd.rs | 15 +- src/tools/miri/src/shims/unix/mod.rs | 2 +- src/tools/miri/src/shims/unix/socket.rs | 16 +- 6 files changed, 193 insertions(+), 201 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 18a41f6c667ca..566988cba1f82 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -2,8 +2,10 @@ //! standard file descriptors (stdin/stdout/stderr). use std::any::Any; +use std::cell::{Ref, RefCell, RefMut}; use std::collections::BTreeMap; use std::io::{self, ErrorKind, IsTerminal, Read, SeekFrom, Write}; +use std::rc::Rc; use rustc_middle::ty::TyCtxt; use rustc_target::abi::Size; @@ -12,7 +14,7 @@ use crate::shims::unix::*; use crate::*; /// Represents an open file descriptor. -pub trait FileDescriptor: std::fmt::Debug + Any { +pub trait FileDescription: std::fmt::Debug + Any { fn name(&self) -> &'static str; fn read<'tcx>( @@ -44,13 +46,10 @@ pub trait FileDescriptor: std::fmt::Debug + Any { fn close<'tcx>( self: Box, _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx, io::Result<()>> { throw_unsup_format!("cannot close {}", self.name()); } - /// Return a new file descriptor *that refers to the same underlying object*. - fn dup(&mut self) -> io::Result>; - fn is_tty(&self, _communicate_allowed: bool) -> bool { // Most FDs are not tty's and the consequence of a wrong `false` are minor, // so we use a default impl here. @@ -58,7 +57,7 @@ pub trait FileDescriptor: std::fmt::Debug + Any { } } -impl dyn FileDescriptor { +impl dyn FileDescription { #[inline(always)] pub fn downcast_ref(&self) -> Option<&T> { (self as &dyn Any).downcast_ref() @@ -70,7 +69,7 @@ impl dyn FileDescriptor { } } -impl FileDescriptor for io::Stdin { +impl FileDescription for io::Stdin { fn name(&self) -> &'static str { "stdin" } @@ -88,16 +87,12 @@ impl FileDescriptor for io::Stdin { Ok(Read::read(self, bytes)) } - fn dup(&mut self) -> io::Result> { - Ok(Box::new(io::stdin())) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } } -impl FileDescriptor for io::Stdout { +impl FileDescription for io::Stdout { fn name(&self) -> &'static str { "stdout" } @@ -120,16 +115,12 @@ impl FileDescriptor for io::Stdout { Ok(result) } - fn dup(&mut self) -> io::Result> { - Ok(Box::new(io::stdout())) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } } -impl FileDescriptor for io::Stderr { +impl FileDescription for io::Stderr { fn name(&self) -> &'static str { "stderr" } @@ -145,10 +136,6 @@ impl FileDescriptor for io::Stderr { Ok(Write::write(&mut { self }, bytes)) } - fn dup(&mut self) -> io::Result> { - Ok(Box::new(io::stderr())) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -158,7 +145,7 @@ impl FileDescriptor for io::Stderr { #[derive(Debug)] pub struct NullOutput; -impl FileDescriptor for NullOutput { +impl FileDescription for NullOutput { fn name(&self) -> &'static str { "stderr and stdout" } @@ -172,16 +159,30 @@ impl FileDescriptor for NullOutput { // We just don't write anything, but report to the user that we did. Ok(Ok(bytes.len())) } +} + +#[derive(Clone, Debug)] +pub struct FileDescriptor(Rc>>); + +impl FileDescriptor { + pub fn new(fd: T) -> Self { + FileDescriptor(Rc::new(RefCell::new(Box::new(fd)))) + } - fn dup(&mut self) -> io::Result> { - Ok(Box::new(NullOutput)) + pub fn close<'ctx>(self, communicate_allowed: bool) -> InterpResult<'ctx, io::Result<()>> { + // Destroy this `Rc` using `into_inner` so we can call `close` instead of + // implicitly running the destructor of the file description. + match Rc::into_inner(self.0) { + Some(fd) => RefCell::into_inner(fd).close(communicate_allowed), + None => Ok(Ok(())), + } } } /// The file descriptor table #[derive(Debug)] pub struct FdTable { - pub fds: BTreeMap>, + pub fds: BTreeMap, } impl VisitProvenance for FdTable { @@ -192,28 +193,24 @@ impl VisitProvenance for FdTable { impl FdTable { pub(crate) fn new(mute_stdout_stderr: bool) -> FdTable { - let mut fds: BTreeMap<_, Box> = BTreeMap::new(); - fds.insert(0i32, Box::new(io::stdin())); + let mut fds: BTreeMap<_, FileDescriptor> = BTreeMap::new(); + fds.insert(0i32, FileDescriptor::new(io::stdin())); if mute_stdout_stderr { - fds.insert(1i32, Box::new(NullOutput)); - fds.insert(2i32, Box::new(NullOutput)); + fds.insert(1i32, FileDescriptor::new(NullOutput)); + fds.insert(2i32, FileDescriptor::new(NullOutput)); } else { - fds.insert(1i32, Box::new(io::stdout())); - fds.insert(2i32, Box::new(io::stderr())); + fds.insert(1i32, FileDescriptor::new(io::stdout())); + fds.insert(2i32, FileDescriptor::new(io::stderr())); } FdTable { fds } } - pub fn insert_fd(&mut self, file_handle: Box) -> i32 { + pub fn insert_fd(&mut self, file_handle: FileDescriptor) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } /// Insert a new FD that is at least `min_fd`. - pub fn insert_fd_with_min_fd( - &mut self, - file_handle: Box, - min_fd: i32, - ) -> i32 { + pub fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptor, min_fd: i32) -> i32 { // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use @@ -239,15 +236,22 @@ impl FdTable { new_fd } - pub fn get(&self, fd: i32) -> Option<&dyn FileDescriptor> { - Some(&**self.fds.get(&fd)?) + pub fn get(&self, fd: i32) -> Option> { + let fd = self.fds.get(&fd)?; + Some(Ref::map(fd.0.borrow(), |fd| fd.as_ref())) } - pub fn get_mut(&mut self, fd: i32) -> Option<&mut dyn FileDescriptor> { - Some(&mut **self.fds.get_mut(&fd)?) + pub fn get_mut(&self, fd: i32) -> Option> { + let fd = self.fds.get(&fd)?; + Some(RefMut::map(fd.0.borrow_mut(), |fd| fd.as_mut())) } - pub fn remove(&mut self, fd: i32) -> Option> { + pub fn dup(&self, fd: i32) -> Option { + let fd = self.fds.get(&fd)?; + Some(fd.clone()) + } + + pub fn remove(&mut self, fd: i32) -> Option { self.fds.remove(&fd) } @@ -296,17 +300,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } let start = this.read_scalar(&args[2])?.to_i32()?; - match this.machine.fds.get_mut(fd) { - Some(file_descriptor) => { - let dup_result = file_descriptor.dup(); - match dup_result { - Ok(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)), - Err(e) => { - this.set_last_error_from_io_error(e.kind())?; - Ok(-1) - } - } - } + match this.machine.fds.dup(fd) { + Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)), None => this.fd_not_found(), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { @@ -330,6 +325,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.remove(fd) { let result = file_descriptor.close(this.machine.communicate())?; + // return `0` if close is successful + let result = result.map(|()| 0i32); this.try_unwrap_io_result(result)? } else { this.fd_not_found()? @@ -369,32 +366,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .min(u64::try_from(isize::MAX).unwrap()); let communicate = this.machine.communicate(); - if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { - trace!("read: FD mapped to {:?}", file_descriptor); - // We want to read at most `count` bytes. We are sure that `count` is not negative - // because it was a target's `usize`. Also we are sure that its smaller than - // `usize::MAX` because it is bounded by the host's `isize`. - let mut bytes = vec![0; usize::try_from(count).unwrap()]; - // `File::read` never returns a value larger than `count`, - // so this cannot fail. - let result = file_descriptor - .read(communicate, &mut bytes, *this.tcx)? - .map(|c| i64::try_from(c).unwrap()); - - match result { - Ok(read_bytes) => { - // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.write_bytes_ptr(buf, bytes)?; - Ok(read_bytes) - } - Err(e) => { - this.set_last_error_from_io_error(e.kind())?; - Ok(-1) - } - } - } else { + let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else { trace!("read: FD not found"); - this.fd_not_found() + return this.fd_not_found(); + }; + + trace!("read: FD mapped to {:?}", file_descriptor); + // We want to read at most `count` bytes. We are sure that `count` is not negative + // because it was a target's `usize`. Also we are sure that its smaller than + // `usize::MAX` because it is bounded by the host's `isize`. + let mut bytes = vec![0; usize::try_from(count).unwrap()]; + // `File::read` never returns a value larger than `count`, + // so this cannot fail. + let result = file_descriptor + .read(communicate, &mut bytes, *this.tcx)? + .map(|c| i64::try_from(c).unwrap()); + drop(file_descriptor); + + match result { + Ok(read_bytes) => { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.write_bytes_ptr(buf, bytes)?; + Ok(read_bytes) + } + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(-1) + } } } @@ -419,13 +417,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let communicate = this.machine.communicate(); let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned(); - if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { - let result = file_descriptor - .write(communicate, &bytes, *this.tcx)? - .map(|c| i64::try_from(c).unwrap()); - this.try_unwrap_io_result(result) - } else { - this.fd_not_found() - } + let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else { + return this.fd_not_found(); + }; + + let result = file_descriptor + .write(communicate, &bytes, *this.tcx)? + .map(|c| i64::try_from(c).unwrap()); + drop(file_descriptor); + + this.try_unwrap_io_result(result) } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 0bf0e3d52c3c1..058747916c0ac 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -17,15 +17,17 @@ use crate::shims::unix::*; use crate::*; use shims::time::system_time_to_duration; +use self::fd::FileDescriptor; + #[derive(Debug)] struct FileHandle { file: File, writable: bool, } -impl FileDescriptor for FileHandle { +impl FileDescription for FileHandle { fn name(&self) -> &'static str { - "FILE" + "file" } fn read<'tcx>( @@ -60,16 +62,14 @@ impl FileDescriptor for FileHandle { fn close<'tcx>( self: Box, communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { + ) -> InterpResult<'tcx, io::Result<()>> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); // We sync the file if it was opened in a mode different than read-only. if self.writable { // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. - let result = self.file.sync_all().map(|_| 0i32); - // Now we actually close the file. - drop(self); - // And return the result. + let result = self.file.sync_all(); + // Now we actually close the file and return the result. Ok(result) } else { // We drop the file, this closes it but ignores any errors @@ -78,16 +78,10 @@ impl FileDescriptor for FileHandle { // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 // for a deeper discussion. - drop(self); - Ok(Ok(0)) + Ok(Ok(())) } } - fn dup(&mut self) -> io::Result> { - let duplicated = self.file.try_clone()?; - Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.file.is_terminal() } @@ -399,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let fd = options.open(path).map(|file| { let fh = &mut this.machine.fds; - fh.insert_fd(Box::new(FileHandle { file, writable })) + fh.insert_fd(FileDescriptor::new(FileHandle { file, writable })) }); this.try_unwrap_io_result(fd) @@ -428,14 +422,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { }; let communicate = this.machine.communicate(); - Ok(Scalar::from_i64(if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { - let result = file_descriptor - .seek(communicate, seek_from)? - .map(|offset| i64::try_from(offset).unwrap()); - this.try_unwrap_io_result(result)? - } else { - this.fd_not_found()? - })) + + let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else { + return Ok(Scalar::from_i64(this.fd_not_found()?)); + }; + let result = file_descriptor + .seek(communicate, seek_from)? + .map(|offset| i64::try_from(offset).unwrap()); + drop(file_descriptor); + + let result = this.try_unwrap_io_result(result)?; + Ok(Scalar::from_i64(result)) } fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1131,32 +1128,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { return Ok(Scalar::from_i32(this.fd_not_found()?)); } - Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { - // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = - file_descriptor.downcast_ref::().ok_or_else(|| { - err_unsup_format!( - "`ftruncate64` is only supported on file-backed file descriptors" - ) - })?; - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32))? - } else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - -1 - } + let Some(file_descriptor) = this.machine.fds.get(fd) else { + return Ok(Scalar::from_i32(this.fd_not_found()?)); + }; + + // FIXME: Support ftruncate64 for all FDs + let FileHandle { file, writable } = + file_descriptor.downcast_ref::().ok_or_else(|| { + err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors") + })?; + + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + drop(file_descriptor); + let result = this.try_unwrap_io_result(result.map(|_| 0i32))?; + Ok(Scalar::from_i32(result)) } else { - // The file is not writable + drop(file_descriptor); let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - -1 + Ok(Scalar::from_i32(-1)) } } else { - this.fd_not_found()? - })) + drop(file_descriptor); + // The file is not writable + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + Ok(Scalar::from_i32(-1)) + } } fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1190,6 +1190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { err_unsup_format!("`fsync` is only supported on file-backed file descriptors") })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); + drop(file_descriptor); this.try_unwrap_io_result(io_result) } @@ -1214,6 +1215,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors") })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); + drop(file_descriptor); this.try_unwrap_io_result(io_result) } @@ -1263,6 +1265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); + drop(file_descriptor); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } @@ -1498,7 +1501,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match file { Ok(f) => { let fh = &mut this.machine.fds; - let fd = fh.insert_fd(Box::new(FileHandle { file: f, writable: true })); + let fd = + fh.insert_fd(FileDescriptor::new(FileHandle { file: f, writable: true })); return Ok(fd); } Err(e) => @@ -1563,21 +1567,21 @@ impl FileMetadata { ecx: &mut MiriInterpCx<'_, 'tcx>, fd: i32, ) -> InterpResult<'tcx, Option> { - let option = ecx.machine.fds.get(fd); - let file = match option { - Some(file_descriptor) => - &file_descriptor - .downcast_ref::() - .ok_or_else(|| { - err_unsup_format!( - "obtaining metadata is only supported on file-backed file descriptors" - ) - })? - .file, - None => return ecx.fd_not_found().map(|_: i32| None), + let Some(file_descriptor) = ecx.machine.fds.get(fd) else { + return ecx.fd_not_found().map(|_: i32| None); }; - let metadata = file.metadata(); + let file = &file_descriptor + .downcast_ref::() + .ok_or_else(|| { + err_unsup_format!( + "obtaining metadata is only supported on file-backed file descriptors" + ) + })? + .file; + + let metadata = file.metadata(); + drop(file_descriptor); FileMetadata::from_meta(ecx, metadata) } diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 5161d91ca3639..48a0ba0197608 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -5,6 +5,8 @@ use rustc_data_structures::fx::FxHashMap; use crate::shims::unix::*; use crate::*; +use self::shims::unix::fd::FileDescriptor; + /// An `Epoll` file descriptor connects file handles and epoll events #[derive(Clone, Debug, Default)] struct Epoll { @@ -29,22 +31,16 @@ struct EpollEvent { data: Scalar, } -impl FileDescriptor for Epoll { +impl FileDescription for Epoll { fn name(&self) -> &'static str { "epoll" } - fn dup(&mut self) -> io::Result> { - // FIXME: this is probably wrong -- check if the `dup`ed descriptor truly uses an - // independent event set. - Ok(Box::new(self.clone())) - } - fn close<'tcx>( self: Box, _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - Ok(Ok(0)) + ) -> InterpResult<'tcx, io::Result<()>> { + Ok(Ok(())) } } @@ -70,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("epoll_create1 flags {flags} are not implemented"); } - let fd = this.machine.fds.insert_fd(Box::new(Epoll::default())); + let fd = this.machine.fds.insert_fd(FileDescriptor::new(Epoll::default())); Ok(Scalar::from_i32(fd)) } @@ -114,27 +110,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let data = this.read_scalar(&data)?; let event = EpollEvent { events, data }; - if let Some(epfd) = this.machine.fds.get_mut(epfd) { - let epfd = epfd - .downcast_mut::() - .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; + let Some(mut epfd) = this.machine.fds.get_mut(epfd) else { + return Ok(Scalar::from_i32(this.fd_not_found()?)); + }; + let epfd = epfd + .downcast_mut::() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; - epfd.file_descriptors.insert(fd, event); - Ok(Scalar::from_i32(0)) - } else { - Ok(Scalar::from_i32(this.fd_not_found()?)) - } + epfd.file_descriptors.insert(fd, event); + Ok(Scalar::from_i32(0)) } else if op == epoll_ctl_del { - if let Some(epfd) = this.machine.fds.get_mut(epfd) { - let epfd = epfd - .downcast_mut::() - .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; - - epfd.file_descriptors.remove(&fd); - Ok(Scalar::from_i32(0)) - } else { - Ok(Scalar::from_i32(this.fd_not_found()?)) - } + let Some(mut epfd) = this.machine.fds.get_mut(epfd) else { + return Ok(Scalar::from_i32(this.fd_not_found()?)); + }; + let epfd = epfd + .downcast_mut::() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; + + epfd.file_descriptors.remove(&fd); + Ok(Scalar::from_i32(0)) } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -185,15 +179,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let _maxevents = this.read_scalar(maxevents)?.to_i32()?; let _timeout = this.read_scalar(timeout)?.to_i32()?; - if let Some(epfd) = this.machine.fds.get_mut(epfd) { - let _epfd = epfd - .downcast_mut::() - .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; + let Some(mut epfd) = this.machine.fds.get_mut(epfd) else { + return Ok(Scalar::from_i32(this.fd_not_found()?)); + }; + let _epfd = epfd + .downcast_mut::() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; - // FIXME return number of events ready when scheme for marking events ready exists - throw_unsup_format!("returning ready events from epoll_wait is not yet implemented"); - } else { - Ok(Scalar::from_i32(this.fd_not_found()?)) - } + // FIXME return number of events ready when scheme for marking events ready exists + throw_unsup_format!("returning ready events from epoll_wait is not yet implemented"); } } diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index 452527017feb3..a865f2efff957 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -8,6 +8,8 @@ use rustc_target::abi::Endian; use crate::shims::unix::*; use crate::*; +use self::shims::unix::fd::FileDescriptor; + /// A kind of file descriptor created by `eventfd`. /// The `Event` type isn't currently written to by `eventfd`. /// The interface is meant to keep track of objects associated @@ -22,21 +24,16 @@ struct Event { val: u64, } -impl FileDescriptor for Event { +impl FileDescription for Event { fn name(&self) -> &'static str { "event" } - fn dup(&mut self) -> io::Result> { - // FIXME: this is wrong, the new and old FD should refer to the same event object! - Ok(Box::new(Event { val: self.val })) - } - fn close<'tcx>( self: Box, _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - Ok(Ok(0)) + ) -> InterpResult<'tcx, io::Result<()>> { + Ok(Ok(())) } /// A write call adds the 8-byte integer value supplied in @@ -115,7 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); } - let fd = this.machine.fds.insert_fd(Box::new(Event { val: val.into() })); + let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { val: val.into() })); Ok(Scalar::from_i32(fd)) } } diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 144593aa2fc08..bede2fbd3897a 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -13,7 +13,7 @@ mod linux; mod macos; pub use env::UnixEnvVars; -pub use fd::{FdTable, FileDescriptor}; +pub use fd::{FdTable, FileDescription}; pub use fs::DirTable; // All the Unix-specific extension traits pub use env::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index 84ddd746fb584..11fd83f57e67e 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -3,26 +3,24 @@ use std::io; use crate::shims::unix::*; use crate::*; +use self::fd::FileDescriptor; + /// Pair of connected sockets. /// /// We currently don't allow sending any data through this pair, so this can be just a dummy. #[derive(Debug)] struct SocketPair; -impl FileDescriptor for SocketPair { +impl FileDescription for SocketPair { fn name(&self) -> &'static str { "socketpair" } - fn dup(&mut self) -> io::Result> { - Ok(Box::new(SocketPair)) - } - fn close<'tcx>( self: Box, _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - Ok(Ok(0)) + ) -> InterpResult<'tcx, io::Result<()>> { + Ok(Ok(())) } } @@ -52,9 +50,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // FIXME: fail on unsupported inputs let fds = &mut this.machine.fds; - let sv0 = fds.insert_fd(Box::new(SocketPair)); + let sv0 = fds.insert_fd(FileDescriptor::new(SocketPair)); let sv0 = Scalar::try_from_int(sv0, sv.layout.size).unwrap(); - let sv1 = fds.insert_fd(Box::new(SocketPair)); + let sv1 = fds.insert_fd(FileDescriptor::new(SocketPair)); let sv1 = Scalar::try_from_int(sv1, sv.layout.size).unwrap(); this.write_scalar(sv0, &sv)?; From da6a18ee0a690778a27e25a49217823ced7d2086 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 10:58:52 +0200 Subject: [PATCH 32/47] speed up Windows runner: don't run GC_STRESS test --- src/tools/miri/ci/ci.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index c8c24ba5da61a..6945b39032365 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,9 +154,9 @@ case $HOST_TARGET in ;; i686-pc-windows-msvc) # Host - # With reduced many-seeds count as this is the slowest runner already. + # Without GC_STRESS and with reduced many-seeds count as this is the slowest runner. # (The macOS runner checks windows-msvc with full many-seeds count.) - GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=16 TEST_BENCH=1 run_tests + MIR_OPT=1 MANY_SEEDS=16 TEST_BENCH=1 run_tests # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, # and a 64bit target works on a 32bit host. From 4ea88d586dc1ae89fa71be4db44e251b2eab53b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 11:46:10 +0200 Subject: [PATCH 33/47] show time taken in run_tests_minimal --- src/tools/miri/ci/ci.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 6945b39032365..3962138635b2b 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -107,10 +107,10 @@ function run_tests_minimal { exit 1 fi - ./miri test -- "$@" + time ./miri test -- "$@" # Ensure that a small smoke test of cargo-miri works. - cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml --target ${MIRI_TEST_TARGET-$HOST_TARGET} + time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml --target ${MIRI_TEST_TARGET-$HOST_TARGET} endgroup } From e944afd04439657b4361db4b13bf8e866914a25e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 11:55:17 +0200 Subject: [PATCH 34/47] move available-parallelism tests into shims/ folder --- .../tests/pass/{ => shims}/available-parallelism-miri-num-cpus.rs | 0 src/tools/miri/tests/pass/{ => shims}/available-parallelism.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/tools/miri/tests/pass/{ => shims}/available-parallelism-miri-num-cpus.rs (100%) rename src/tools/miri/tests/pass/{ => shims}/available-parallelism.rs (100%) diff --git a/src/tools/miri/tests/pass/available-parallelism-miri-num-cpus.rs b/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs similarity index 100% rename from src/tools/miri/tests/pass/available-parallelism-miri-num-cpus.rs rename to src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs diff --git a/src/tools/miri/tests/pass/available-parallelism.rs b/src/tools/miri/tests/pass/shims/available-parallelism.rs similarity index 100% rename from src/tools/miri/tests/pass/available-parallelism.rs rename to src/tools/miri/tests/pass/shims/available-parallelism.rs From 6b82ec2a761db7be9c3e1c883d274447edb5ea94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 12:29:36 +0200 Subject: [PATCH 35/47] rename integer test --- src/tools/miri/tests/pass/{ints.rs => integers.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tools/miri/tests/pass/{ints.rs => integers.rs} (100%) diff --git a/src/tools/miri/tests/pass/ints.rs b/src/tools/miri/tests/pass/integers.rs similarity index 100% rename from src/tools/miri/tests/pass/ints.rs rename to src/tools/miri/tests/pass/integers.rs From 5648735bd8ca2cb203332f88759a26eac0349677 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 12:34:16 +0200 Subject: [PATCH 36/47] move intrinsics implementations and tests into dedicated folder and make them separate from 'shims' --- src/tools/miri/src/{shims => }/intrinsics/atomic.rs | 0 src/tools/miri/src/{shims => }/intrinsics/mod.rs | 0 src/tools/miri/src/{shims => }/intrinsics/simd.rs | 0 src/tools/miri/src/lib.rs | 3 ++- src/tools/miri/src/shims/mod.rs | 1 - .../fail/{shims => intrinsics}/intrinsic_target_feature.rs | 0 .../fail/{shims => intrinsics}/intrinsic_target_feature.stderr | 0 .../pass/{intrinsics-integer.rs => intrinsics/integer.rs} | 0 src/tools/miri/tests/pass/{ => intrinsics}/intrinsics.rs | 0 .../miri/tests/pass/{ => intrinsics}/portable-simd-ptrs.rs | 0 src/tools/miri/tests/pass/{ => intrinsics}/portable-simd.rs | 0 src/tools/miri/tests/pass/{ => intrinsics}/volatile.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-aes-vaes.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-avx.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-avx2.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-avx512.rs | 0 .../pass/{ => shims/x86}/intrinsics-x86-pause-without-sse2.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse2.rs | 0 .../tests/pass/{ => shims/x86}/intrinsics-x86-sse3-ssse3.rs | 0 .../miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse41.rs | 0 src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86.rs | 0 22 files changed, 2 insertions(+), 2 deletions(-) rename src/tools/miri/src/{shims => }/intrinsics/atomic.rs (100%) rename src/tools/miri/src/{shims => }/intrinsics/mod.rs (100%) rename src/tools/miri/src/{shims => }/intrinsics/simd.rs (100%) rename src/tools/miri/tests/fail/{shims => intrinsics}/intrinsic_target_feature.rs (100%) rename src/tools/miri/tests/fail/{shims => intrinsics}/intrinsic_target_feature.stderr (100%) rename src/tools/miri/tests/pass/{intrinsics-integer.rs => intrinsics/integer.rs} (100%) rename src/tools/miri/tests/pass/{ => intrinsics}/intrinsics.rs (100%) rename src/tools/miri/tests/pass/{ => intrinsics}/portable-simd-ptrs.rs (100%) rename src/tools/miri/tests/pass/{ => intrinsics}/portable-simd.rs (100%) rename src/tools/miri/tests/pass/{ => intrinsics}/volatile.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-aes-vaes.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-avx.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-avx2.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-avx512.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-pause-without-sse2.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse2.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse3-ssse3.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86-sse41.rs (100%) rename src/tools/miri/tests/pass/{ => shims/x86}/intrinsics-x86.rs (100%) diff --git a/src/tools/miri/src/shims/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs similarity index 100% rename from src/tools/miri/src/shims/intrinsics/atomic.rs rename to src/tools/miri/src/intrinsics/atomic.rs diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs similarity index 100% rename from src/tools/miri/src/shims/intrinsics/mod.rs rename to src/tools/miri/src/intrinsics/mod.rs diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs similarity index 100% rename from src/tools/miri/src/shims/intrinsics/simd.rs rename to src/tools/miri/src/intrinsics/simd.rs diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index f47c84842b17f..f01c2da25d9e2 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -79,6 +79,7 @@ mod concurrency; mod diagnostics; mod eval; mod helpers; +mod intrinsics; mod machine; mod mono_hash_map; mod operator; @@ -95,9 +96,9 @@ pub use rustc_const_eval::interpret::*; #[doc(no_inline)] pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; +pub use crate::intrinsics::EvalContextExt as _; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; -pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 85c9a202f7daf..ab5a8c5877ec2 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -5,7 +5,6 @@ mod backtrace; #[cfg(target_os = "linux")] pub mod ffi_support; pub mod foreign_items; -pub mod intrinsics; pub mod unix; pub mod windows; mod x86; diff --git a/src/tools/miri/tests/fail/shims/intrinsic_target_feature.rs b/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.rs similarity index 100% rename from src/tools/miri/tests/fail/shims/intrinsic_target_feature.rs rename to src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.rs diff --git a/src/tools/miri/tests/fail/shims/intrinsic_target_feature.stderr b/src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.stderr similarity index 100% rename from src/tools/miri/tests/fail/shims/intrinsic_target_feature.stderr rename to src/tools/miri/tests/fail/intrinsics/intrinsic_target_feature.stderr diff --git a/src/tools/miri/tests/pass/intrinsics-integer.rs b/src/tools/miri/tests/pass/intrinsics/integer.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-integer.rs rename to src/tools/miri/tests/pass/intrinsics/integer.rs diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics.rs rename to src/tools/miri/tests/pass/intrinsics/intrinsics.rs diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs similarity index 100% rename from src/tools/miri/tests/pass/portable-simd-ptrs.rs rename to src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs similarity index 100% rename from src/tools/miri/tests/pass/portable-simd.rs rename to src/tools/miri/tests/pass/intrinsics/portable-simd.rs diff --git a/src/tools/miri/tests/pass/volatile.rs b/src/tools/miri/tests/pass/intrinsics/volatile.rs similarity index 100% rename from src/tools/miri/tests/pass/volatile.rs rename to src/tools/miri/tests/pass/intrinsics/volatile.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-avx.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-avx2.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-avx512.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-sse.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-sse2.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse3-ssse3.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse3-ssse3.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse41.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse41.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86-sse41.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse41.rs diff --git a/src/tools/miri/tests/pass/intrinsics-x86.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86.rs similarity index 100% rename from src/tools/miri/tests/pass/intrinsics-x86.rs rename to src/tools/miri/tests/pass/shims/x86/intrinsics-x86.rs From f43e3e2023f28d7e7a9f870612c6f2ef867a2acb Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 4 May 2024 12:37:30 +0200 Subject: [PATCH 37/47] Fix ignored tests for formatting --- rustfmt.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rustfmt.toml b/rustfmt.toml index 67219b15d203d..850d01ea7cb81 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -13,6 +13,12 @@ ignore = [ # tests for now are not formatted, as they are sometimes pretty-printing constrained # (and generally rustfmt can move around comments in UI-testing incompatible ways) + "/tests/*", + + # but we still want to format rmake.rs files in tests/run-make/ so we need to do this + # dance to avoid the parent directory from being excluded + "!/tests/run-make/", + "/tests/run-make/*/*.rs", "!/tests/run-make/*/rmake.rs", # do not format submodules From c484fd27a9726b1a9ec19d45b8c19b660a4f70c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 12:39:37 +0200 Subject: [PATCH 38/47] fix grouping of target-specific LLVM shims --- src/tools/miri/src/shims/foreign_items.rs | 60 +++++++++++------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 4b96ff18b74cb..6a12180b836b7 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -893,36 +893,6 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("unsupported `llvm.prefetch` type argument: {}", ty); } } - // FIXME: Move these to an `arm` submodule. - "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; - let arg = this.read_scalar(arg)?.to_i32()?; - match arg { - // SY ("full system scope") - 15 => { - this.yield_active_thread(); - } - _ => { - throw_unsup_format!("unsupported llvm.aarch64.isb argument {}", arg); - } - } - } - "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => { - let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; - let arg = this.read_scalar(arg)?.to_i32()?; - // Note that different arguments might have different target feature requirements. - match arg { - // YIELD - 1 => { - this.expect_target_feature_for_intrinsic(link_name, "v6")?; - this.yield_active_thread(); - } - _ => { - throw_unsup_format!("unsupported llvm.arm.hint argument {}", arg); - } - } - } - // 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") => { @@ -946,6 +916,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } + // Target-specific shims name if name.starts_with("llvm.x86.") && (this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64") => @@ -954,6 +925,35 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this, link_name, abi, args, dest, ); } + // FIXME: Move these to an `arm` submodule. + "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { + let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let arg = this.read_scalar(arg)?.to_i32()?; + match arg { + // SY ("full system scope") + 15 => { + this.yield_active_thread(); + } + _ => { + throw_unsup_format!("unsupported llvm.aarch64.isb argument {}", arg); + } + } + } + "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => { + let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let arg = this.read_scalar(arg)?.to_i32()?; + // Note that different arguments might have different target feature requirements. + match arg { + // YIELD + 1 => { + this.expect_target_feature_for_intrinsic(link_name, "v6")?; + this.yield_active_thread(); + } + _ => { + throw_unsup_format!("unsupported llvm.arm.hint argument {}", arg); + } + } + } // Platform-specific shims _ => From d7ad3dac6371c1732d2f96189d5c6caa7f1e12e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 10:56:53 +0200 Subject: [PATCH 39/47] move some minimal targets over to the macOS runner, to even out CI times --- src/tools/miri/ci/ci.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 3962138635b2b..67835960bd7ce 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -130,9 +130,16 @@ case $HOST_TARGET in MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests + ;; + aarch64-apple-darwin) + # Host (tier 2) + GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + # Extra tier 1 + MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests + MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests # Extra tier 2 - MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests + MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice # Partially supported targets (tier 2) MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus @@ -143,15 +150,6 @@ case $HOST_TARGET in # Custom target JSON file MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std ;; - aarch64-apple-darwin) - # Host (tier 2) - GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests - # Extra tier 1 - MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests - MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests - # Extra tier 2 - MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture - ;; i686-pc-windows-msvc) # Host # Without GC_STRESS and with reduced many-seeds count as this is the slowest runner. From ab2168b344c1bc64823a4ab13fbf60d1498a5670 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 13:45:54 +0200 Subject: [PATCH 40/47] update 'unsupported' message --- src/tools/miri/README.md | 2 +- src/tools/miri/src/diagnostics.rs | 5 ++++- .../miri/tests/extern-so/fail/function_not_in_so.stderr | 3 ++- src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr | 3 ++- .../miri/tests/fail-dep/shims/fs/read_from_stdout.stderr | 3 ++- src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr | 3 ++- src/tools/miri/tests/fail-dep/tokio/sleep.stderr | 3 ++- .../tests/fail-dep/unsupported_incomplete_function.stderr | 3 ++- src/tools/miri/tests/fail/alloc/no_global_allocator.stderr | 3 ++- src/tools/miri/tests/fail/extern-type-field-offset.stderr | 3 ++- src/tools/miri/tests/fail/extern_static.stderr | 3 ++- src/tools/miri/tests/fail/extern_static_in_const.stderr | 3 ++- src/tools/miri/tests/fail/extern_static_wrong_size.stderr | 3 ++- ...sue-miri-3288-ice-symbolic-alignment-extern-static.stderr | 3 ++- .../tests/fail/shims/backtrace/bad-backtrace-flags.stderr | 3 ++- .../fail/shims/backtrace/bad-backtrace-resolve-flags.stderr | 3 ++- .../shims/backtrace/bad-backtrace-resolve-names-flags.stderr | 3 ++- .../fail/shims/backtrace/bad-backtrace-size-flags.stderr | 3 ++- .../promise_alignment.call_unaligned_ptr.stderr | 3 ++- .../fail/unaligned_pointers/promise_alignment_zero.stderr | 3 ++- src/tools/miri/tests/fail/unsized-local.stderr | 3 ++- .../miri/tests/fail/unsupported_foreign_function.stderr | 3 ++- 22 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index ef01ca25fb0b4..5b088abcbe626 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -141,7 +141,7 @@ interpreter will explicitly tell you when it finds something unsupported: error: unsupported operation: can't call foreign function: bind ... = help: this is likely not a bug in the program; it indicates that the program \ - performed an operation that the interpreter does not support + performed an operation that Miri does not support ``` ### Cross-interpretation: running for different targets diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 9fa786332e3cd..5fac922f56833 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -320,7 +320,10 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match e.kind() { Unsupported(_) => - vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], + vec![ + (None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support")), + (None, format!("if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there")), + ], UndefinedBehavior(AlignmentCheckFailed { .. }) if ecx.machine.check_alignment == AlignmentCheck::Symbolic => diff --git a/src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr b/src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr index c031cb0146ad6..26761c48721df 100644 --- a/src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr +++ b/src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr @@ -4,7 +4,8 @@ error: unsupported operation: can't call foreign function `foo` on $OS LL | foo(); | ^^^^^ can't call foreign function `foo` on $OS | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/function_not_in_so.rs:LL:CC diff --git a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr index 7547ec417194c..e50480157657b 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr +++ b/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr @@ -4,7 +4,8 @@ error: unsupported operation: cannot close stdout LL | libc::close(1); | ^^^^^^^^^^^^^^ cannot close stdout | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/close_stdout.rs:LL:CC diff --git a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr b/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr index 355e16d5c3498..fb0fb8acc3f11 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr +++ b/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr @@ -4,7 +4,8 @@ error: unsupported operation: cannot read from stdout LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC diff --git a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr b/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr index e2ebe234b0bb0..8426c5cb84732 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr +++ b/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr @@ -4,7 +4,8 @@ error: unsupported operation: cannot write to stdin LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC diff --git a/src/tools/miri/tests/fail-dep/tokio/sleep.stderr b/src/tools/miri/tests/fail-dep/tokio/sleep.stderr index 59179478c3025..f7d829f77d2bd 100644 --- a/src/tools/miri/tests/fail-dep/tokio/sleep.stderr +++ b/src/tools/miri/tests/fail-dep/tokio/sleep.stderr @@ -9,7 +9,8 @@ LL | | timeout, LL | | )) | |__________^ returning ready events from epoll_wait is not yet implemented | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr b/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr index fabe3bbf1216a..23327ff7dbd57 100644 --- a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr +++ b/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr @@ -4,7 +4,8 @@ error: unsupported operation: can't call foreign function `signal` on $OS LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `signal` on $OS | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/unsupported_incomplete_function.rs:LL:CC diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr index bd2a6c628f9e5..70f60a3f591f6 100644 --- a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr +++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr @@ -4,7 +4,8 @@ error: unsupported operation: can't call foreign function `__rust_alloc` on $OS LL | __rust_alloc(1, 1); | ^^^^^^^^^^^^^^^^^^ can't call foreign function `__rust_alloc` on $OS | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC diff --git a/src/tools/miri/tests/fail/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr index cbbf1b3836199..14609ec699cea 100644 --- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr +++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr @@ -4,7 +4,8 @@ error: unsupported operation: `extern type` does not have a known offset LL | let _field = &x.a; | ^^^^ `extern type` does not have a known offset | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/extern-type-field-offset.rs:LL:CC diff --git a/src/tools/miri/tests/fail/extern_static.stderr b/src/tools/miri/tests/fail/extern_static.stderr index 34bb273f04be0..1d12fd76bedb7 100644 --- a/src/tools/miri/tests/fail/extern_static.stderr +++ b/src/tools/miri/tests/fail/extern_static.stderr @@ -4,7 +4,8 @@ error: unsupported operation: extern static `FOO` is not supported by Miri LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; | ^^^ extern static `FOO` is not supported by Miri | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/extern_static.rs:LL:CC diff --git a/src/tools/miri/tests/fail/extern_static_in_const.stderr b/src/tools/miri/tests/fail/extern_static_in_const.stderr index 45d1632cce2ee..455d6af18e417 100644 --- a/src/tools/miri/tests/fail/extern_static_in_const.stderr +++ b/src/tools/miri/tests/fail/extern_static_in_const.stderr @@ -4,7 +4,8 @@ error: unsupported operation: extern static `E` is not supported by Miri LL | let _val = X; | ^ extern static `E` is not supported by Miri | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC diff --git a/src/tools/miri/tests/fail/extern_static_wrong_size.stderr b/src/tools/miri/tests/fail/extern_static_wrong_size.stderr index 27699d780c228..91afb936facb9 100644 --- a/src/tools/miri/tests/fail/extern_static_wrong_size.stderr +++ b/src/tools/miri/tests/fail/extern_static_wrong_size.stderr @@ -4,7 +4,8 @@ error: unsupported operation: extern static `environ` has been declared as `exte LL | let _val = unsafe { environ }; | ^^^^^^^ extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr index e5dbe749884cc..0d10b03fc4f4d 100644 --- a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr @@ -4,7 +4,8 @@ error: unsupported operation: extern static `_dispatch_queue_attr_concurrent` is LL | let _val = *DISPATCH_QUEUE_CONCURRENT; | ^^^^^^^^^^^^^^^^^^^^^^^^^ extern static `_dispatch_queue_attr_concurrent` is not supported by Miri | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr index 2523e5063e1b5..ced44ee776840 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-flags.stderr @@ -4,7 +4,8 @@ error: unsupported operation: unknown `miri_get_backtrace` flags 2 LL | miri_get_backtrace(2, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr index 36446ae283bf7..6e282ff4908aa 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr @@ -4,7 +4,8 @@ error: unsupported operation: unknown `miri_resolve_frame` flags 2 LL | miri_resolve_frame(buf[0], 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr index ff60ab09172fd..ddf8d221cc41f 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -4,7 +4,8 @@ error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr index 6d4c370050f49..b3186fc5b0769 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr @@ -4,7 +4,8 @@ error: unsupported operation: unknown `miri_backtrace_size` flags 2 LL | miri_backtrace_size(2); | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr index e23ac5ac2fc5d..9ad715f7ba4ae 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment.call_unaligned_ptr.stderr @@ -4,7 +4,8 @@ error: unsupported operation: `miri_promise_symbolic_alignment`: pointer is not LL | unsafe { utils::miri_promise_symbolic_alignment(align8.add(1).cast(), 8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `miri_promise_symbolic_alignment`: pointer is not actually aligned | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/promise_alignment.rs:LL:CC diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr index b3327e04933d5..62b6e85231107 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr @@ -4,7 +4,8 @@ error: unsupported operation: `miri_promise_symbolic_alignment`: alignment must LL | unsafe { utils::miri_promise_symbolic_alignment(buffer.as_ptr().cast(), 0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `miri_promise_symbolic_alignment`: alignment must be a power of 2, got 0 | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/promise_alignment_zero.rs:LL:CC diff --git a/src/tools/miri/tests/fail/unsized-local.stderr b/src/tools/miri/tests/fail/unsized-local.stderr index 0ffda9e6d6317..d938f36bd5ec7 100644 --- a/src/tools/miri/tests/fail/unsized-local.stderr +++ b/src/tools/miri/tests/fail/unsized-local.stderr @@ -4,7 +4,8 @@ error: unsupported operation: unsized locals are not supported LL | let x = *(Box::new(A) as Box); | ^ unsized locals are not supported | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/unsized-local.rs:LL:CC diff --git a/src/tools/miri/tests/fail/unsupported_foreign_function.stderr b/src/tools/miri/tests/fail/unsupported_foreign_function.stderr index 5a2f415bb84b0..7492fdd77bbac 100644 --- a/src/tools/miri/tests/fail/unsupported_foreign_function.stderr +++ b/src/tools/miri/tests/fail/unsupported_foreign_function.stderr @@ -4,7 +4,8 @@ error: unsupported operation: can't call foreign function `foo` on $OS LL | foo(); | ^^^^^ can't call foreign function `foo` on $OS | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = help: if this is a basic API commonly used on this target, please report an issue; but note that Miri does not aim to support every FFI function out there = note: BACKTRACE: = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC From 4529e67fee280e0c5ec5451aacf97bee2891d5f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 11:48:16 +0200 Subject: [PATCH 41/47] freebsd: test std threadname and fs APIs also reorder foreign_items to fix the grouping, and reorder the tests_minimal invocations to be more consistent --- src/tools/miri/ci/ci.sh | 12 ++++--- .../src/shims/unix/freebsd/foreign_items.rs | 32 +++++++++---------- .../{thread_name.rs => threadname.rs} | 0 3 files changed, 23 insertions(+), 21 deletions(-) rename src/tools/miri/tests/pass/concurrency/{thread_name.rs => threadname.rs} (100%) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 67835960bd7ce..d3dee0de617fe 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -141,11 +141,13 @@ case $HOST_TARGET in MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice # Partially supported targets (tier 2) - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus - MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus - MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic - MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm - MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm + VERY_BASIC="integer vec string btreemap" # common things we test on all of them (if they have std), requires no target-specific shims + BASIC="$VERY_BASIC hello hashmap alloc align" # ensures we have the shims for stdout and basic data structures + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-getentropy libc-getrandom libc-misc fs env num_cpus + MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-getentropy libc-getrandom libc-misc fs env num_cpus + MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal $VERY_BASIC hello panic/panic + MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal $VERY_BASIC wasm + MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal $VERY_BASIC wasm MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # Custom target JSON file MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std 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 ffb583123d41b..3db9b9c1db580 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -47,21 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.read_scalar(len)?, )?; } - "getrandom" => { - let [ptr, len, flags] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_pointer(ptr)?; - let len = this.read_target_usize(len)?; - let _flags = this.read_scalar(flags)?.to_i32()?; - // flags on freebsd does not really matter - // in practice, GRND_RANDOM does not particularly draw from /dev/random - // since it is the same as to /dev/urandom. - // GRND_INSECURE is only an alias of GRND_NONBLOCK, which - // does not affect the RNG. - // https://man.freebsd.org/cgi/man.cgi?query=getrandom&sektion=2&n=1 - this.gen_random(ptr, len)?; - this.write_scalar(Scalar::from_target_usize(len, this), dest)?; - } // File related shims // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases @@ -90,7 +75,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(result, dest)?; } - // errno + // Miscellaneous + "getrandom" => { + let [ptr, len, flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let ptr = this.read_pointer(ptr)?; + let len = this.read_target_usize(len)?; + let _flags = this.read_scalar(flags)?.to_i32()?; + // flags on freebsd does not really matter + // in practice, GRND_RANDOM does not particularly draw from /dev/random + // since it is the same as to /dev/urandom. + // GRND_INSECURE is only an alias of GRND_NONBLOCK, which + // does not affect the RNG. + // https://man.freebsd.org/cgi/man.cgi?query=getrandom&sektion=2&n=1 + this.gen_random(ptr, len)?; + this.write_scalar(Scalar::from_target_usize(len, this), dest)?; + } "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; diff --git a/src/tools/miri/tests/pass/concurrency/thread_name.rs b/src/tools/miri/tests/pass/concurrency/threadname.rs similarity index 100% rename from src/tools/miri/tests/pass/concurrency/thread_name.rs rename to src/tools/miri/tests/pass/concurrency/threadname.rs From 86bd0a8457cd3d5e37c20fa7e3a540b45b51ea72 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 11:49:24 +0200 Subject: [PATCH 42/47] document unofficially supported OSes --- src/tools/miri/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index ef01ca25fb0b4..616426bd838eb 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -224,8 +224,11 @@ degree documented below): - `s390x-unknown-linux-gnu` is supported as our "big-endian target of choice". - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we make no promises and we don't run tests for such targets. -- For targets on other operating systems, even basic operations such as printing to the standard - output might not work, and Miri might fail before even reaching the `main` function. +- We have unofficial support (not maintained by the Miri team itself) for some further operating systems. + - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. + - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. + - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. +- For targets on other operating systems, Miri might fail before even reaching the `main` function. However, even for targets that we do support, the degree of support for accessing platform APIs (such as the file system) differs between targets: generally, Linux targets have the best support, From 99c5151048613fde1f48a5940bc34f48c6150c5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 13:00:59 +0200 Subject: [PATCH 43/47] make some tests not need output (so they work on wasm) --- src/tools/miri/tests/pass/align_offset_symbolic.rs | 5 ++++- src/tools/miri/tests/pass/align_offset_symbolic.stdout | 1 - src/tools/miri/tests/pass/vecdeque.rs | 4 ++-- src/tools/miri/tests/pass/vecdeque.stack.stdout | 2 -- src/tools/miri/tests/pass/vecdeque.tree.stdout | 2 -- src/tools/miri/tests/pass/vecdeque.tree_uniq.stdout | 2 -- 6 files changed, 6 insertions(+), 10 deletions(-) delete mode 100644 src/tools/miri/tests/pass/align_offset_symbolic.stdout delete mode 100644 src/tools/miri/tests/pass/vecdeque.stack.stdout delete mode 100644 src/tools/miri/tests/pass/vecdeque.tree.stdout delete mode 100644 src/tools/miri/tests/pass/vecdeque.tree_uniq.stdout diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs index c32fa2c8f9bda..dec3d779a789a 100644 --- a/src/tools/miri/tests/pass/align_offset_symbolic.rs +++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs @@ -62,7 +62,10 @@ fn test_from_utf8() { const N: usize = 10; let vec = vec![0x4141414141414141u64; N]; let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; - println!("{:?}", std::str::from_utf8(content).unwrap()); + assert_eq!( + std::str::from_utf8(content).unwrap(), + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + ); } fn test_u64_array() { diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.stdout b/src/tools/miri/tests/pass/align_offset_symbolic.stdout deleted file mode 100644 index 66d4399481596..0000000000000 --- a/src/tools/miri/tests/pass/align_offset_symbolic.stdout +++ /dev/null @@ -1 +0,0 @@ -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs index ccecf3d30a414..77c4ca5a04e6a 100644 --- a/src/tools/miri/tests/pass/vecdeque.rs +++ b/src/tools/miri/tests/pass/vecdeque.rs @@ -31,8 +31,8 @@ fn main() { } // Regression test for Debug impl's - println!("{:?} {:?}", dst, dst.iter()); - println!("{:?}", VecDeque::::new().iter()); + format!("{:?} {:?}", dst, dst.iter()); + format!("{:?}", VecDeque::::new().iter()); for a in dst { assert_eq!(*a, 2); diff --git a/src/tools/miri/tests/pass/vecdeque.stack.stdout b/src/tools/miri/tests/pass/vecdeque.stack.stdout deleted file mode 100644 index 63de960ee2bdf..0000000000000 --- a/src/tools/miri/tests/pass/vecdeque.stack.stdout +++ /dev/null @@ -1,2 +0,0 @@ -[2, 2] Iter([2, 2], []) -Iter([], []) diff --git a/src/tools/miri/tests/pass/vecdeque.tree.stdout b/src/tools/miri/tests/pass/vecdeque.tree.stdout deleted file mode 100644 index 63de960ee2bdf..0000000000000 --- a/src/tools/miri/tests/pass/vecdeque.tree.stdout +++ /dev/null @@ -1,2 +0,0 @@ -[2, 2] Iter([2, 2], []) -Iter([], []) diff --git a/src/tools/miri/tests/pass/vecdeque.tree_uniq.stdout b/src/tools/miri/tests/pass/vecdeque.tree_uniq.stdout deleted file mode 100644 index 63de960ee2bdf..0000000000000 --- a/src/tools/miri/tests/pass/vecdeque.tree_uniq.stdout +++ /dev/null @@ -1,2 +0,0 @@ -[2, 2] Iter([2, 2], []) -Iter([], []) From 8bffd88373394b8dfb9c0bdea1094687c0733c8d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 14:26:11 +0200 Subject: [PATCH 44/47] add helper function to declare an extern static for a weak symbol --- src/tools/miri/src/shims/extern_static.rs | 22 ++++++++++++++----- src/tools/miri/src/shims/foreign_items.rs | 9 ++++++++ .../miri/src/shims/unix/foreign_items.rs | 2 +- .../src/shims/unix/linux/foreign_items.rs | 2 -- .../miri/src/shims/windows/foreign_items.rs | 2 +- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 442338a6117d8..5cec51e960484 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -29,6 +29,21 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { Ok(()) } + /// Extern statics that are initialized with function pointers to the symbols of the same name. + fn weak_symbol_extern_statics( + this: &mut MiriInterpCx<'mir, 'tcx>, + names: &[&str], + ) -> InterpResult<'tcx> { + for name in names { + assert!(this.is_dyn_sym(name), "{name} is not a dynamic symbol"); + let layout = this.machine.layouts.const_raw_ptr; + let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); + let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); + Self::alloc_extern_static(this, name, val)?; + } + Ok(()) + } + /// Sets up the "extern statics" for this machine. pub fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { // "__rust_no_alloc_shim_is_unstable" @@ -58,12 +73,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { } "android" => { Self::null_ptr_extern_statics(this, &["bsd_signal"])?; - // "signal" -- just needs a non-zero pointer value (function does not even get called), - // but we arrange for this to call the `signal` function anyway. - let layout = this.machine.layouts.const_raw_ptr; - let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal"))); - let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); - Self::alloc_extern_static(this, "signal", val)?; + Self::weak_symbol_extern_statics(this, &["signal"])?; } "windows" => { // "_tls_used" diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 6a12180b836b7..4f8bb801100c1 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -151,6 +151,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(None) } + fn is_dyn_sym(&self, name: &str) -> bool { + let this = self.eval_context_ref(); + match this.tcx.sess.target.os.as_ref() { + os if this.target_os_is_unix() => shims::unix::foreign_items::is_dyn_sym(name, os), + "windows" => shims::windows::foreign_items::is_dyn_sym(name), + _ => false, + } + } + /// Emulates a call to a `DynSym`. fn emulate_dyn_sym( &mut self, diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index bd299aaa1253a..bebf8b4b8a542 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -15,7 +15,7 @@ use shims::unix::freebsd::foreign_items as freebsd; use shims::unix::linux::foreign_items as linux; use shims::unix::macos::foreign_items as macos; -fn is_dyn_sym(name: &str, target_os: &str) -> bool { +pub fn is_dyn_sym(name: &str, target_os: &str) -> bool { match name { // Used for tests. "isatty" => true, 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 497e8bee70ec9..58ffd5fc1e037 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -113,9 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // have the right type. let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?; - let sys_statx = this.eval_libc("SYS_statx").to_target_usize(this)?; - let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?; if args.is_empty() { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index e8ae80261c662..7b156ee311a0a 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -15,7 +15,7 @@ use crate::*; use shims::foreign_items::EmulateForeignItemResult; use shims::windows::handle::{Handle, PseudoHandle}; -fn is_dyn_sym(name: &str) -> bool { +pub fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols matches!( name, From 1572c0dcd7b5d9e4fcd400d3b34f1d675201f150 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 1 May 2024 17:37:22 +0200 Subject: [PATCH 45/47] Various improvements to entrypoint code This moves some code around and adds some documentation comments to make it easier to understand what's going on with the entrypoint logic, which is a bit complicated. The only change in behavior is consolidating the error messages for unix_sigpipe to make the code slightly simpler. --- compiler/rustc_ast/src/entry.rs | 26 +++++++++++- .../rustc_builtin_macros/src/test_harness.rs | 2 +- compiler/rustc_passes/messages.ftl | 6 --- compiler/rustc_passes/src/entry.rs | 42 ++++++++++--------- compiler/rustc_passes/src/errors.rs | 16 ------- 5 files changed, 49 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index cd8a5a6692000..dd231e286d591 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -4,11 +4,35 @@ use rustc_span::Symbol; #[derive(Debug)] pub enum EntryPointType { + /// This function is not an entrypoint. None, + /// This is a function called `main` at the root level. + /// ``` + /// fn main() {} + /// ``` MainNamed, + /// This is a function with the `#[rustc_main]` attribute. + /// Used by the testing harness to create the test entrypoint. + /// ```ignore (clashes with test entrypoint) + /// #[rustc_main] + /// fn main() {} + /// ``` RustcMainAttr, + /// This is a function with the `#[start]` attribute. + /// ```ignore (clashes with test entrypoint) + /// #[start] + /// fn main() {} + /// ``` Start, - OtherMain, // Not an entry point, but some other function named main + /// This function is **not** an entrypoint but simply named `main` (not at the root). + /// This is only used for diagnostics. + /// ``` + /// #[allow(dead_code)] + /// mod meow { + /// fn main() {} + /// } + /// ``` + OtherMain, } pub fn entry_point_type( diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a2015445b42c9..8cf431482ff73 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -266,7 +266,7 @@ fn generate_test_harness( /// /// By default this expands to /// -/// ```ignore UNSOLVED (I think I still need guidance for this one. Is it correct? Do we try to make it run? How do we nicely fill it out?) +/// ```ignore (messes with test internals) /// #[rustc_main] /// pub fn main() { /// extern crate test; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 8878310d6e93f..9d58d301e2bc2 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -49,12 +49,6 @@ passes_attr_crate_level = passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions -passes_attr_only_on_main = - `{$attr}` attribute can only be used on `fn main()` - -passes_attr_only_on_root_main = - `{$attr}` attribute can only be used on root `fn main()` - passes_both_ffi_const_and_pure = `#[ffi_const]` function cannot be `#[ffi_pure]` diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index d52092f2aa92a..b43c8282db1db 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -18,10 +18,10 @@ use crate::errors::{ struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, - /// The function that has attribute named `main`. - attr_main_fn: Option<(LocalDefId, Span)>, + /// The function has the `#[rustc_main]` attribute. + rustc_main_fn: Option<(LocalDefId, Span)>, - /// The function that has the attribute 'start' on it. + /// The function that has the attribute `#[start]` on it. start_fn: Option<(LocalDefId, Span)>, /// The functions that one might think are `main` but aren't, e.g. @@ -42,10 +42,10 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } let mut ctxt = - EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; + EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; for id in tcx.hir().items() { - find_item(id, &mut ctxt); + check_and_search_item(id, &mut ctxt); } configure_main(tcx, &ctxt) @@ -56,7 +56,16 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti attr::find_by_name(attrs, sym).map(|attr| attr.span) } -fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { +fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { + if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) { + for attr in [sym::start, sym::rustc_main] { + if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { + ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); + } + } + return; + } + let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); let attrs = ctxt.tcx.hir().attrs(id.hir_id()); @@ -65,26 +74,20 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { at_root, ctxt.tcx.opt_item_name(id.owner_id.to_def_id()), ); + match entry_point_type { - EntryPointType::None => (), - _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => { - for attr in [sym::start, sym::rustc_main] { - if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { - ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); - } - } - } - EntryPointType::MainNamed => (), + EntryPointType::None => {} + EntryPointType::MainNamed => {} EntryPointType::OtherMain => { ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id)); } EntryPointType::RustcMainAttr => { - if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); + if ctxt.rustc_main_fn.is_none() { + ctxt.rustc_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { ctxt.tcx.dcx().emit_err(MultipleRustcMain { span: ctxt.tcx.def_span(id.owner_id.to_def_id()), - first: ctxt.attr_main_fn.unwrap().1, + first: ctxt.rustc_main_fn.unwrap().1, additional: ctxt.tcx.def_span(id.owner_id.to_def_id()), }); } @@ -107,10 +110,11 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> { if let Some((def_id, _)) = visitor.start_fn { Some((def_id.to_def_id(), EntryFnType::Start)) - } else if let Some((local_def_id, _)) = visitor.attr_main_fn { + } else if let Some((local_def_id, _)) = visitor.rustc_main_fn { let def_id = local_def_id.to_def_id(); Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) })) } else { + // The actual resolution of main happens in the resolver, this here if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 743faf5456078..65cad82cc8c2b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1206,22 +1206,6 @@ pub struct NakedFunctionsMustUseNoreturn { pub last_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_attr_only_on_main)] -pub struct AttrOnlyOnMain { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - -#[derive(Diagnostic)] -#[diag(passes_attr_only_on_root_main)] -pub struct AttrOnlyOnRootMain { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions { From 99f77acc0fbfd00f2dd3557d0499950a1fc589ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 14:41:12 +0200 Subject: [PATCH 46/47] make statx a regular function (so we don't need to support the syscall) --- src/tools/miri/src/shims/extern_static.rs | 7 +++--- src/tools/miri/src/shims/unix/fd.rs | 4 +++ .../src/shims/unix/linux/foreign_items.rs | 25 ++++++------------- .../miri/tests/pass/alloc-access-tracking.rs | 5 ++-- .../tests/pass/alloc-access-tracking.stderr | 8 +++--- 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 5cec51e960484..c3c7ef7c1fd8e 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -16,8 +16,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { /// Zero-initialized pointer-sized extern statics are pretty common. /// Most of them are for weak symbols, which we all set to null (indicating that the - /// symbol is not supported, and triggering fallback code which ends up calling a - /// syscall that we do support). + /// symbol is not supported, and triggering fallback code which ends up calling + /// some other shim that we do support). fn null_ptr_extern_statics( this: &mut MiriInterpCx<'mir, 'tcx>, names: &[&str], @@ -59,8 +59,9 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { "linux" => { Self::null_ptr_extern_statics( this, - &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"], + &["__cxa_thread_atexit_impl", "__clock_gettime64"], )?; + Self::weak_symbol_extern_statics(this, &["getrandom", "statx"])?; // "environ" let environ = this.machine.env_vars.unix().environ(); Self::add_extern_static(this, "environ", environ); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 566988cba1f82..e536b78d1c0bc 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -17,6 +17,7 @@ use crate::*; pub trait FileDescription: std::fmt::Debug + Any { fn name(&self) -> &'static str; + /// Reads as much as possible into the given buffer, and returns the number of bytes read. fn read<'tcx>( &mut self, _communicate_allowed: bool, @@ -26,6 +27,7 @@ pub trait FileDescription: std::fmt::Debug + Any { throw_unsup_format!("cannot read from {}", self.name()); } + /// Writes as much as possible from the given buffer, and returns the number of bytes written. fn write<'tcx>( &mut self, _communicate_allowed: bool, @@ -35,6 +37,8 @@ pub trait FileDescription: std::fmt::Debug + Any { throw_unsup_format!("cannot write to {}", self.name()); } + /// Seeks to the given offset (which can be relative to the beginning, end, or current position). + /// Returns the new position from the start of the stream. fn seek<'tcx>( &mut self, _communicate_allowed: bool, 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 58ffd5fc1e037..71cdc3be81470 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -12,7 +12,7 @@ use shims::unix::linux::mem::EvalContextExt as _; use shims::unix::linux::sync::futex; pub fn is_dyn_sym(name: &str) -> bool { - matches!(name, "getrandom") + matches!(name, "getrandom" | "statx") } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. match link_name.as_str() { - // File related shims (but also see "syscall" below for statx) + // File related shims "readdir64" => { let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64(dirp)?; @@ -41,6 +41,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(result, dest)?; } + "statx" => { + let [dirfd, pathname, flags, mask, statxbuf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // epoll, eventfd "epoll_create1" => { @@ -113,7 +119,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // have the right type. let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?; - let sys_statx = this.eval_libc("SYS_statx").to_target_usize(this)?; let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?; if args.is_empty() { @@ -134,20 +139,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } getrandom(this, &args[1], &args[2], &args[3], dest)?; } - // `statx` is used by `libstd` to retrieve metadata information on `linux` - // instead of using `stat`,`lstat` or `fstat` as on `macos`. - id if id == sys_statx => { - // The first argument is the syscall id, so skip over it. - if args.len() < 6 { - throw_ub_format!( - "incorrect number of arguments for `statx` syscall: got {}, expected at least 6", - args.len() - ); - } - let result = - this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; - this.write_scalar(Scalar::from_target_isize(result.into(), this), dest)?; - } // `futex` is used by some synchronization primitives. id if id == sys_futex => { futex(this, &args[1..], dest)?; diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 29c1ee2f7b765..a226783155b42 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,7 +1,8 @@ #![feature(start)] #![no_std] -//@compile-flags: -Zmiri-track-alloc-id=18 -Zmiri-track-alloc-accesses -Cpanic=abort -//@only-target-linux: alloc IDs differ between OSes for some reason +//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort +//@normalize-stderr-test: "id 20" -> "id $$ALLOC" +//@only-target-linux: alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { fn miri_alloc(size: usize, align: usize) -> *mut u8; diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr index bef13701ea2c4..0af6cde833f7f 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr +++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr @@ -2,7 +2,7 @@ note: tracking was triggered --> $DIR/alloc-access-tracking.rs:LL:CC | LL | let ptr = miri_alloc(123, 1); - | ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id 18 + | ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC | = note: BACKTRACE: = note: inside `start` at $DIR/alloc-access-tracking.rs:LL:CC @@ -11,7 +11,7 @@ note: tracking was triggered --> $DIR/alloc-access-tracking.rs:LL:CC | LL | *ptr = 42; // Crucially, only a write is printed here, no read! - | ^^^^^^^^^ write access to allocation with id 18 + | ^^^^^^^^^ write access to allocation with id $ALLOC | = note: BACKTRACE: = note: inside `start` at $DIR/alloc-access-tracking.rs:LL:CC @@ -20,7 +20,7 @@ note: tracking was triggered --> $DIR/alloc-access-tracking.rs:LL:CC | LL | assert_eq!(*ptr, 42); - | ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id 18 + | ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id $ALLOC | = note: BACKTRACE: = note: inside `start` at RUSTLIB/core/src/macros/mod.rs:LL:CC @@ -30,7 +30,7 @@ note: tracking was triggered --> $DIR/alloc-access-tracking.rs:LL:CC | LL | miri_dealloc(ptr, 123, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id 18 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id $ALLOC | = note: BACKTRACE: = note: inside `start` at $DIR/alloc-access-tracking.rs:LL:CC From dc0cc728816c63dcec36e75f46d826a317bdcef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 May 2024 15:49:47 +0200 Subject: [PATCH 47/47] update lockfile --- Cargo.lock | 88 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e4db4fdd53eb..dd2d7a25de5b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,6 +512,28 @@ dependencies = [ "windows-targets 0.52.4", ] +[[package]] +name = "chrono-tz" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf 0.11.2", +] + +[[package]] +name = "chrono-tz-build" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +dependencies = [ + "parse-zoneinfo", + "phf 0.11.2", + "phf_codegen 0.11.2", +] + [[package]] name = "cipher" version = "0.4.4" @@ -2318,8 +2340,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" dependencies = [ "log", - "phf", - "phf_codegen", + "phf 0.10.1", + "phf_codegen 0.10.0", "string_cache", "string_cache_codegen", "tendril", @@ -2480,6 +2502,7 @@ version = "0.1.0" dependencies = [ "aes", "chrono", + "chrono-tz", "colored", "ctrlc", "directories", @@ -2835,6 +2858,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + [[package]] name = "pathdiff" version = "0.2.1" @@ -2907,7 +2939,16 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ - "phf_shared", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared 0.11.2", ] [[package]] @@ -2916,8 +2957,18 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", ] [[package]] @@ -2926,7 +2977,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ - "phf_shared", + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", "rand", ] @@ -2939,6 +3000,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -5289,7 +5359,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot", - "phf_shared", + "phf_shared 0.10.0", "precomputed-hash", "serde", ] @@ -5300,8 +5370,8 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro2", "quote", ]