about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs2
-rwxr-xr-xsrc/tools/miri/ci.sh3
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs12
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/helpers.rs11
-rw-r--r--src/tools/miri/src/range_map.rs1
-rw-r--r--src/tools/miri/src/shims/env.rs6
-rw-r--r--src/tools/miri/src/shims/os_str.rs51
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs40
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock81
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml4
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr4
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr2
-rw-r--r--src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs57
-rw-r--r--src/tools/miri/tests/pass/shims/env/current_exe.rs1
17 files changed, 246 insertions, 35 deletions
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index e51bfa3798f..37f66d0033f 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -185,7 +185,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the
     // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host
     // builds.
-    cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap());
+    cmd.env("RUSTC", fs::canonicalize(find_miri()).unwrap());
     cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases!
 
     // Set rustdoc to us as well, so we can run doctests.
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index b35f7370d68..e01bfbc74d9 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -108,7 +108,8 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
     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
+    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings
+    MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings
     MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
     MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
     ;;
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index ee75e7a2932..cf6d9c28080 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-4f4d0586ad20c66a16d547581ca379beafece93a
+c54c8cbac882e149e04a9e1f2d146fd548ae30ae
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index 5f132bf11a9..2cc8f035466 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -88,11 +88,7 @@ impl fmt::Display for InvalidationCause {
         match self {
             InvalidationCause::Access(kind) => write!(f, "{kind}"),
             InvalidationCause::Retag(perm, kind) =>
-                if *kind == RetagCause::FnEntry {
-                    write!(f, "{perm:?} FnEntry retag")
-                } else {
-                    write!(f, "{perm:?} retag")
-                },
+                write!(f, "{perm:?} {retag}", retag = kind.summary()),
         }
     }
 }
@@ -193,7 +189,7 @@ struct RetagOp {
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum RetagCause {
     Normal,
-    FnReturn,
+    FnReturnPlace,
     FnEntry,
     TwoPhase,
 }
@@ -495,8 +491,8 @@ impl RetagCause {
     fn summary(&self) -> String {
         match self {
             RetagCause::Normal => "retag",
-            RetagCause::FnEntry => "FnEntry retag",
-            RetagCause::FnReturn => "FnReturn retag",
+            RetagCause::FnEntry => "function-entry retag",
+            RetagCause::FnReturnPlace => "return-place retag",
             RetagCause::TwoPhase => "two-phase retag",
         }
         .to_string()
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index bcdf2e75179..ec555ba2895 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -998,7 +998,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             access: Some(AccessKind::Write),
             protector: Some(ProtectorKind::StrongProtector),
         };
-        let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturn)?;
+        let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturnPlace)?;
         // And use reborrowed pointer for return place.
         let return_place = this.ref_to_mplace(&val)?;
         this.frame_mut().return_place = return_place.into();
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index c11c6104c28..527d31d1f0a 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -943,7 +943,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         link_name: Symbol,
     ) -> InterpResult<'tcx, ()> {
         self.check_abi(abi, exp_abi)?;
-        if let Some((body, _)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
+        if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
+            // If compiler-builtins is providing the symbol, then don't treat it as a clash.
+            // We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased
+            // performance. Note that this means we won't catch any undefined behavior in
+            // compiler-builtins when running other crates, but Miri can still be run on
+            // compiler-builtins itself (or any crate that uses it as a normal dependency)
+            if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) {
+                return Ok(());
+            }
+
             throw_machine_stop!(TerminationInfo::SymbolShimClashing {
                 link_name,
                 span: body.span.data(),
diff --git a/src/tools/miri/src/range_map.rs b/src/tools/miri/src/range_map.rs
index c8ff06a3665..62198061827 100644
--- a/src/tools/miri/src/range_map.rs
+++ b/src/tools/miri/src/range_map.rs
@@ -219,7 +219,6 @@ mod tests {
     /// Query the map at every offset in the range and collect the results.
     fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
         (offset..offset + len)
-            .into_iter()
             .map(|i| {
                 map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()
             })
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index e049eec57a3..ce24b23ca32 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -166,7 +166,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 // `buf_size` represents the size in characters.
                 let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?);
                 Scalar::from_u32(windows_check_buffer_size(
-                    this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?,
+                    this.write_os_str_to_wide_str(
+                        &var, buf_ptr, buf_size, /*truncate*/ false,
+                    )?,
                 ))
             }
             None => {
@@ -366,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         match env::current_dir() {
             Ok(cwd) =>
                 return Ok(Scalar::from_u32(windows_check_buffer_size(
-                    this.write_path_to_wide_str(&cwd, buf, size)?,
+                    this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?,
                 ))),
             Err(e) => this.set_last_error_from_io_error(e.kind())?,
         }
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index 0375a228a21..f010d4251f4 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -101,17 +101,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         self.eval_context_mut().write_c_str(bytes, ptr, size)
     }
 
-    /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what
-    /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
-    /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
-    /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
-    /// string length returned does include the null terminator. Length is measured in units of
-    /// `u16.`
+    /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
+    /// Windows APIs usually handle.
+    ///
+    /// If `truncate == false` (the usual mode of operation), this function returns `Ok((false,
+    /// length))` without trying to write if `size` is not large enough to fit the contents of
+    /// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process
+    /// was successful. The string length returned does include the null terminator. Length is
+    /// measured in units of `u16.`
+    ///
+    /// If `truncate == true`, then in case `size` is not large enough it *will* write the first
+    /// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`).
     fn write_os_str_to_wide_str(
         &mut self,
         os_str: &OsStr,
         ptr: Pointer<Option<Provenance>>,
         size: u64,
+        truncate: bool,
     ) -> InterpResult<'tcx, (bool, u64)> {
         #[cfg(windows)]
         fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
@@ -129,7 +135,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
 
         let u16_vec = os_str_to_u16vec(os_str)?;
-        self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)
+        let (written, size_needed) = self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)?;
+        if truncate && !written && size > 0 {
+            // Write the truncated part that fits.
+            let truncated_data = &u16_vec[..size.saturating_sub(1).try_into().unwrap()];
+            let (written, written_len) =
+                self.eval_context_mut().write_wide_str(truncated_data, ptr, size)?;
+            assert!(written && written_len == size);
+        }
+        Ok((written, size_needed))
     }
 
     /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
@@ -143,7 +157,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let arg_type = this.tcx.mk_array(this.tcx.types.u8, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
-        assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0);
+        let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
+        assert!(written);
         Ok(arg_place.ptr)
     }
 
@@ -158,7 +173,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let arg_type = this.tcx.mk_array(this.tcx.types.u16, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
-        assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0);
+        let (written, _) =
+            self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap();
+        assert!(written);
         Ok(arg_place.ptr)
     }
 
@@ -212,11 +229,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         path: &Path,
         ptr: Pointer<Option<Provenance>>,
         size: u64,
+        truncate: bool,
     ) -> InterpResult<'tcx, (bool, u64)> {
         let this = self.eval_context_mut();
         let os_str =
             this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
-        this.write_os_str_to_wide_str(&os_str, ptr, size)
+        this.write_os_str_to_wide_str(&os_str, ptr, size, truncate)
     }
 
     /// Allocate enough memory to store a Path as a null-terminated sequence of bytes,
@@ -232,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.alloc_os_str_as_c_str(&os_str, memkind)
     }
 
+    /// Allocate enough memory to store a Path as a null-terminated sequence of `u16`s,
+    /// adjusting path separators if needed.
+    fn alloc_path_as_wide_str(
+        &mut self,
+        path: &Path,
+        memkind: MemoryKind<MiriMemoryKind>,
+    ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
+        let this = self.eval_context_mut();
+        let os_str =
+            this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
+        this.alloc_os_str_as_wide_str(&os_str, memkind)
+    }
+
     #[allow(clippy::get_first)]
     fn convert_path<'a>(
         &self,
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 1da8f7c0e3e..f310d16e861 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -381,6 +381,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 this.write_scalar(Scalar::from_u32(1), dest)?;
             }
+            "GetModuleFileNameW" => {
+                let [handle, filename, size] =
+                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+                this.check_no_isolation("`GetModuleFileNameW`")?;
+
+                let handle = this.read_machine_usize(handle)?;
+                let filename = this.read_pointer(filename)?;
+                let size = this.read_scalar(size)?.to_u32()?;
+
+                if handle != 0 {
+                    throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
+                }
+
+                // Using the host current_exe is a bit off, but consistent with Linux
+                // (where stdlib reads /proc/self/exe).
+                // Unfortunately this Windows function has a crazy behavior so we can't just use
+                // `write_path_to_wide_str`...
+                let path = std::env::current_exe().unwrap();
+                let (all_written, size_needed) = this.write_path_to_wide_str(
+                    &path,
+                    filename,
+                    size.into(),
+                    /*truncate*/ true,
+                )?;
+
+                if all_written {
+                    // If the function succeeds, the return value is the length of the string that
+                    // is copied to the buffer, in characters, not including the terminating null
+                    // character.
+                    this.write_int(size_needed.checked_sub(1).unwrap(), dest)?;
+                } else {
+                    // If the buffer is too small to hold the module name, the string is truncated
+                    // to nSize characters including the terminating null character, the function
+                    // returns nSize, and the function sets the last error to
+                    // ERROR_INSUFFICIENT_BUFFER.
+                    this.write_int(size, dest)?;
+                    let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
+                    this.set_last_error(insufficient_buffer)?;
+                }
+            }
 
             // Threading
             "CreateThread" => {
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index bf7f0411bed..a84ed859763 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -15,6 +15,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
+[[package]]
 name = "bytes"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -44,8 +50,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
+ "js-sys",
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -58,6 +66,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
 name = "libc"
 version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -124,6 +141,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "once_cell"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
+
+[[package]]
 name = "page_size"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -269,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.23.0"
+version = "1.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
+checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8"
 dependencies = [
  "autocfg",
  "bytes",
@@ -317,6 +340,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 1df35bbbe2f..f5ab6acf008 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -13,11 +13,11 @@ libc = "0.2"
 num_cpus = "1.10.1"
 
 getrandom_1 = { package = "getrandom", version = "0.1" }
-getrandom = { version = "0.2" }
+getrandom = { version = "0.2", features = ["js"] }
 rand = { version = "0.8", features = ["small_rng"] }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
 page_size = "0.5"
-tokio = { version = "1.0", features = ["full"] }
+tokio = { version = "1.23", features = ["full"] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr b/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
index 55aaed62f4f..ae54d0248dc 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
@@ -5,7 +5,7 @@ LL | pub fn safe(_x: &mut i32, _y: &i32) {}
    |                           ^^
    |                           |
    |                           trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
-   |                           this error occurs as part of FnEntry retag at ALLOC[0x0..0x4]
+   |                           this error occurs as part of function-entry retag at ALLOC[0x0..0x4]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
    |
 LL |     safe_raw(xraw, xshr);
    |                    ^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call
   --> $DIR/aliasing_mut3.rs:LL:CC
    |
 LL |     safe_raw(xraw, xshr);
diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr
index e3bffde1f01..236c8fb0187 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
    |
 LL |     let z = &mut x as *mut i32;
    |             ^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call
   --> $DIR/fnentry_invalidation.rs:LL:CC
    |
 LL |     x.do_bad();
diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr
index b104de4b8d9..45c2197050a 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0xc]
    |
 LL |     let ptr = t.sli.as_ptr();
    |               ^^^^^^^^^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0xc] by a Unique FnEntry retag inside this call
+help: <TAG> was later invalidated at offsets [0x0..0xc] by a Unique function-entry retag inside this call
   --> $DIR/fnentry_invalidation2.rs:LL:CC
    |
 LL |     let _ = t.sli.as_mut_ptr();
diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
index 04e89ec361b..7ccafec6037 100644
--- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
+++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
@@ -186,8 +186,65 @@ fn join_orders_after_tls_destructors() {
     }
 }
 
+fn dtors_in_dtors_in_dtors() {
+    use std::cell::UnsafeCell;
+    use std::sync::{Arc, Condvar, Mutex};
+
+    #[derive(Clone, Default)]
+    struct Signal(Arc<(Mutex<bool>, Condvar)>);
+
+    impl Signal {
+        fn notify(&self) {
+            let (set, cvar) = &*self.0;
+            *set.lock().unwrap() = true;
+            cvar.notify_one();
+        }
+
+        fn wait(&self) {
+            let (set, cvar) = &*self.0;
+            let mut set = set.lock().unwrap();
+            while !*set {
+                set = cvar.wait(set).unwrap();
+            }
+        }
+    }
+
+    struct NotifyOnDrop(Signal);
+
+    impl Drop for NotifyOnDrop {
+        fn drop(&mut self) {
+            let NotifyOnDrop(ref f) = *self;
+            f.notify();
+        }
+    }
+
+    struct S1(Signal);
+    thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+    thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None));
+
+    impl Drop for S1 {
+        fn drop(&mut self) {
+            let S1(ref signal) = *self;
+            unsafe {
+                let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone())));
+            }
+        }
+    }
+
+    let signal = Signal::default();
+    let signal2 = signal.clone();
+    let _t = thread::spawn(move || unsafe {
+        let mut signal = Some(signal2);
+        K1.with(|s| *s.get() = Some(S1(signal.take().unwrap())));
+    });
+    // Note that this test will deadlock if TLS destructors aren't run (this
+    // requires the destructor to be run to pass the test).
+    signal.wait();
+}
+
 fn main() {
     check_destructors();
     check_blocking();
     join_orders_after_tls_destructors();
+    dtors_in_dtors_in_dtors();
 }
diff --git a/src/tools/miri/tests/pass/shims/env/current_exe.rs b/src/tools/miri/tests/pass/shims/env/current_exe.rs
index 3f1153d265d..898a42b72d1 100644
--- a/src/tools/miri/tests/pass/shims/env/current_exe.rs
+++ b/src/tools/miri/tests/pass/shims/env/current_exe.rs
@@ -1,4 +1,3 @@
-//@ignore-target-windows: current_exe not supported on Windows
 //@only-on-host: the Linux std implementation opens /proc/self/exe, which doesn't work cross-target
 //@compile-flags: -Zmiri-disable-isolation
 use std::env;