about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/alloc/src/boxed.rs6
-rw-r--r--library/alloc/src/rc.rs6
-rw-r--r--library/alloc/src/string.rs3
-rw-r--r--library/alloc/src/sync.rs6
-rw-r--r--library/alloc/src/vec/into_iter.rs7
-rw-r--r--library/alloc/src/vec/mod.rs6
-rw-r--r--library/core/src/mem/manually_drop.rs3
-rw-r--r--library/core/src/mem/maybe_uninit.rs15
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/src/sync/condvar.rs3
-rw-r--r--library/std/src/sys/pal/windows/alloc.rs129
-rw-r--r--library/std/src/sys/pal/windows/c.rs2
-rw-r--r--library/std/src/sys/pal/windows/c/windows_targets.rs13
-rw-r--r--library/sysroot/Cargo.toml1
-rw-r--r--src/bootstrap/mk/Makefile.in7
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs7
17 files changed, 145 insertions, 75 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 65bcb241e4a..f299aa0124d 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1213,6 +1213,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// let static_ref: &'static mut usize = Box::leak(x);
     /// *static_ref += 1;
     /// assert_eq!(*static_ref, 42);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     ///
     /// Unsized data:
@@ -1222,6 +1225,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// let static_ref = Box::leak(x);
     /// static_ref[0] = 4;
     /// assert_eq!(*static_ref, [4, 2, 3]);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     #[stable(feature = "box_leak", since = "1.26.0")]
     #[inline]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index aa8dd9f79c3..9982c8ea6dc 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1277,6 +1277,8 @@ impl<T: ?Sized> Rc<T> {
     ///
     ///     let five = Rc::from_raw(ptr);
     ///     assert_eq!(2, Rc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Rc::decrement_strong_count(ptr);
     /// }
     /// ```
     #[inline]
@@ -1345,6 +1347,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// let x = Rc::new("hello".to_owned());
     /// let x_ptr = Rc::into_raw(x);
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
+    /// # // Prevent leaks for Miri.
+    /// # drop(unsafe { Rc::from_raw(x_ptr) });
     /// ```
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
@@ -1572,6 +1576,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     ///
     ///     let five = Rc::from_raw_in(ptr, System);
     ///     assert_eq!(2, Rc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Rc::decrement_strong_count_in(ptr, System);
     /// }
     /// ```
     #[inline]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 36078da7c35..07ffd3e1519 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1984,6 +1984,9 @@ impl String {
     /// let x = String::from("bucket");
     /// let static_ref: &'static mut str = x.leak();
     /// assert_eq!(static_ref, "bucket");
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     #[stable(feature = "string_leak", since = "1.72.0")]
     #[inline]
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 57ac20ba323..a905a1e6b7e 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1414,6 +1414,8 @@ impl<T: ?Sized> Arc<T> {
     ///     // the `Arc` between threads.
     ///     let five = Arc::from_raw(ptr);
     ///     assert_eq!(2, Arc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Arc::decrement_strong_count(ptr);
     /// }
     /// ```
     #[inline]
@@ -1484,6 +1486,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// let x = Arc::new("hello".to_owned());
     /// let x_ptr = Arc::into_raw(x);
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
+    /// # // Prevent leaks for Miri.
+    /// # drop(unsafe { Arc::from_raw(x_ptr) });
     /// ```
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
@@ -1766,6 +1770,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     ///     // the `Arc` between threads.
     ///     let five = Arc::from_raw_in(ptr, System);
     ///     assert_eq!(2, Arc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Arc::decrement_strong_count_in(ptr, System);
     /// }
     /// ```
     #[inline]
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 3bd89eaa6cb..10f62e4bb62 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -120,10 +120,15 @@ impl<T, A: Allocator> IntoIter<T, A> {
     /// This is roughly equivalent to the following, but more efficient
     ///
     /// ```
-    /// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter();
+    /// # let mut vec = Vec::<u8>::with_capacity(10);
+    /// # let ptr = vec.as_mut_ptr();
+    /// # let mut into_iter = vec.into_iter();
     /// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter());
     /// (&mut into_iter).for_each(drop);
     /// std::mem::forget(into_iter);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Vec::<u8>::from_raw_parts(ptr, 0, 10) });
     /// ```
     ///
     /// This method is used by in-place iteration, refer to the vec::in_place_collect
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 6e9b017ad75..729d5dd4fe4 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1473,6 +1473,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// // 2. `0 <= capacity` always holds whatever `capacity` is.
     /// unsafe {
     ///     vec.set_len(0);
+    /// #   // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// #   // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// #   vec.set_len(3);
     /// }
     /// ```
     ///
@@ -2391,6 +2394,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// let static_ref: &'static mut [usize] = x.leak();
     /// static_ref[0] += 1;
     /// assert_eq!(static_ref, &[2, 2, 3]);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     #[stable(feature = "vec_leak", since = "1.47.0")]
     #[inline]
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs
index e0c3b9f3b51..997f088c6d6 100644
--- a/library/core/src/mem/manually_drop.rs
+++ b/library/core/src/mem/manually_drop.rs
@@ -62,6 +62,9 @@ impl<T> ManuallyDrop<T> {
     /// x.truncate(5); // You can still safely operate on the value
     /// assert_eq!(*x, "Hello");
     /// // But `Drop` will not be run here
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # let _ = ManuallyDrop::into_inner(x);
     /// ```
     #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"]
     #[stable(feature = "manually_drop", since = "1.20.0")]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 24ebe33bb2c..dd40f57dc87 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -274,6 +274,8 @@ impl<T> MaybeUninit<T> {
     /// use std::mem::MaybeUninit;
     ///
     /// let v: MaybeUninit<Vec<u8>> = MaybeUninit::new(vec![42]);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { let _ = MaybeUninit::assume_init(v); }
     /// ```
     ///
     /// [`assume_init`]: MaybeUninit::assume_init
@@ -446,6 +448,9 @@ impl<T> MaybeUninit<T> {
     /// let mut x = MaybeUninit::<String>::uninit();
     ///
     /// x.write("Hello".to_string());
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
     /// // This leaks the contained string:
     /// x.write("hello".to_string());
     /// // x is initialized now:
@@ -506,6 +511,8 @@ impl<T> MaybeUninit<T> {
     /// // Create a reference into the `MaybeUninit<T>`. This is okay because we initialized it.
     /// let x_vec = unsafe { &*x.as_ptr() };
     /// assert_eq!(x_vec.len(), 3);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
     /// ```
     ///
     /// *Incorrect* usage of this method:
@@ -545,6 +552,8 @@ impl<T> MaybeUninit<T> {
     /// let x_vec = unsafe { &mut *x.as_mut_ptr() };
     /// x_vec.push(3);
     /// assert_eq!(x_vec.len(), 4);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
     /// ```
     ///
     /// *Incorrect* usage of this method:
@@ -746,6 +755,8 @@ impl<T> MaybeUninit<T> {
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
+    /// # let mut x_mu = x;
+    /// # let mut x = &mut x_mu;
     /// // Initialize `x`:
     /// x.write(vec![1, 2, 3]);
     /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to
@@ -755,6 +766,8 @@ impl<T> MaybeUninit<T> {
     ///     x.assume_init_ref()
     /// };
     /// assert_eq!(x, &vec![1, 2, 3]);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x_mu); }
     /// ```
     ///
     /// ### *Incorrect* usages of this method:
@@ -1088,6 +1101,8 @@ impl<T> MaybeUninit<T> {
     /// let init = MaybeUninit::clone_from_slice(&mut dst, &src);
     ///
     /// assert_eq!(init, src);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { std::ptr::drop_in_place(init); }
     /// ```
     ///
     /// ```
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 75a99e14fda..1238061d68d 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1663,6 +1663,8 @@ impl<T> NonNull<[T]> {
     /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized.
     /// # #[allow(unused_variables)]
     /// let slice: &mut [MaybeUninit<u8>] = unsafe { memory.as_uninit_slice_mut() };
+    /// # // Prevent leaks for Miri.
+    /// # unsafe { Global.deallocate(memory.cast(), Layout::new::<[u8; 32]>()); }
     /// # Ok::<_, std::alloc::AllocError>(())
     /// ```
     #[inline]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 358510b8f77..b991b1cf22d 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -87,6 +87,10 @@ std_detect_file_io = ["std_detect/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"]
 std_detect_env_override = ["std_detect/std_detect_env_override"]
 
+# Enable using raw-dylib for Windows imports.
+# This will eventually be the default.
+windows_raw_dylib = []
+
 [package.metadata.fortanix-sgx]
 # Maximum possible number of threads when testing
 threads = 125
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index f9f83fb4f63..08d46f356d9 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -35,6 +35,7 @@ impl WaitTimeoutResult {
     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
     /// let pair2 = Arc::clone(&pair);
     ///
+    /// # let handle =
     /// thread::spawn(move || {
     ///     let (lock, cvar) = &*pair2;
     ///
@@ -58,6 +59,8 @@ impl WaitTimeoutResult {
     ///         break
     ///     }
     /// }
+    /// # // Prevent leaks for Miri.
+    /// # let _ = handle.join();
     /// ```
     #[must_use]
     #[stable(feature = "wait_timeout", since = "1.5.0")]
diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs
index 24c237b5eb0..e6cbdb6ef7d 100644
--- a/library/std/src/sys/pal/windows/alloc.rs
+++ b/library/std/src/sys/pal/windows/alloc.rs
@@ -4,7 +4,7 @@ use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ffi::c_void;
 use crate::ptr;
 use crate::sync::atomic::{AtomicPtr, Ordering};
-use crate::sys::c;
+use crate::sys::c::{self, windows_targets};
 use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
 use core::mem::MaybeUninit;
 
@@ -17,74 +17,71 @@ mod tests;
 // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed.
 const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008;
 
-#[link(name = "kernel32")]
-extern "system" {
-    // Get a handle to the default heap of the current process, or null if the operation fails.
-    //
-    // SAFETY: Successful calls to this function within the same process are assumed to
-    // always return the same handle, which remains valid for the entire lifetime of the process.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap
-    fn GetProcessHeap() -> c::HANDLE;
+// Get a handle to the default heap of the current process, or null if the operation fails.
+//
+// SAFETY: Successful calls to this function within the same process are assumed to
+// always return the same handle, which remains valid for the entire lifetime of the process.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap
+windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE);
 
-    // Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`.
-    // The allocated memory may be uninitialized, or zeroed if `dwFlags` is
-    // set to `HEAP_ZERO_MEMORY`.
-    //
-    // Returns a pointer to the newly-allocated memory or null if the operation fails.
-    // The returned pointer will be aligned to at least `MIN_ALIGN`.
-    //
-    // SAFETY:
-    //  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
-    //  - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`.
-    //
-    // Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
-    fn HeapAlloc(hHeap: c::HANDLE, dwFlags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID;
+// Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`.
+// The allocated memory may be uninitialized, or zeroed if `dwFlags` is
+// set to `HEAP_ZERO_MEMORY`.
+//
+// Returns a pointer to the newly-allocated memory or null if the operation fails.
+// The returned pointer will be aligned to at least `MIN_ALIGN`.
+//
+// SAFETY:
+//  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
+//  - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`.
+//
+// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
+windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void);
 
-    // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
-    // to a block of at least `dwBytes` bytes, either shrinking the block in place,
-    // or allocating at a new location, copying memory, and freeing the original location.
-    //
-    // Returns a pointer to the reallocated memory or null if the operation fails.
-    // The returned pointer will be aligned to at least `MIN_ALIGN`.
-    // If the operation fails the given block will never have been freed.
-    //
-    // SAFETY:
-    //  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
-    //  - `dwFlags` must be set to zero.
-    //  - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or
-    //     `HeapReAlloc`, that has not already been freed.
-    // If the block was successfully reallocated at a new location, pointers pointing to
-    // the freed memory, such as `lpMem`, must not be dereferenced ever again.
-    //
-    // Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc
-    fn HeapReAlloc(
-        hHeap: c::HANDLE,
-        dwFlags: c::DWORD,
-        lpMem: c::LPVOID,
-        dwBytes: c::SIZE_T,
-    ) -> c::LPVOID;
+// Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
+// to a block of at least `dwBytes` bytes, either shrinking the block in place,
+// or allocating at a new location, copying memory, and freeing the original location.
+//
+// Returns a pointer to the reallocated memory or null if the operation fails.
+// The returned pointer will be aligned to at least `MIN_ALIGN`.
+// If the operation fails the given block will never have been freed.
+//
+// SAFETY:
+//  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
+//  - `dwFlags` must be set to zero.
+//  - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or
+//     `HeapReAlloc`, that has not already been freed.
+// If the block was successfully reallocated at a new location, pointers pointing to
+// the freed memory, such as `lpMem`, must not be dereferenced ever again.
+//
+// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc
+windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
+    hheap: c::HANDLE,
+    dwflags : u32,
+    lpmem: *const core::ffi::c_void,
+    dwbytes: usize
+) -> *mut core::ffi::c_void);
 
-    // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`.
-    // Returns a nonzero value if the operation is successful, and zero if the operation fails.
-    //
-    // SAFETY:
-    //  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
-    //  - `dwFlags` must be set to zero.
-    //  - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`,
-    //     that has not already been freed.
-    // If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`,
-    // must not be dereferenced ever again.
-    //
-    // Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
-    fn HeapFree(hHeap: c::HANDLE, dwFlags: c::DWORD, lpMem: c::LPVOID) -> c::BOOL;
-}
+// Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`.
+// Returns a nonzero value if the operation is successful, and zero if the operation fails.
+//
+// SAFETY:
+//  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
+//  - `dwFlags` must be set to zero.
+//  - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`,
+//     that has not already been freed.
+// If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`,
+// must not be dereferenced ever again.
+//
+// Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
+windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL);
 
 // Cached handle to the default heap of the current process.
 // Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed.
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 27aa35f69f1..7dfda4f714c 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -13,7 +13,7 @@ use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_vo
 use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
 use crate::ptr;
 
-mod windows_targets;
+pub(super) mod windows_targets;
 
 mod windows_sys;
 pub use windows_sys::*;
diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs
index 56c563462d3..252bceb7094 100644
--- a/library/std/src/sys/pal/windows/c/windows_targets.rs
+++ b/library/std/src/sys/pal/windows/c/windows_targets.rs
@@ -3,6 +3,18 @@
 //! This is a simple wrapper around an `extern` block with a `#[link]` attribute.
 //! It's very roughly equivalent to the windows-targets crate.
 
+#[cfg(feature = "windows_raw_dylib")]
+pub macro link {
+    ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
+        #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))]
+        #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))]
+        extern $abi {
+            $(#[link_name=$link_name])?
+            pub fn $($function)*;
+        }
+    )
+}
+#[cfg(not(feature = "windows_raw_dylib"))]
 pub macro link {
     ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
         // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't
@@ -17,6 +29,7 @@ pub macro link {
     )
 }
 
+#[cfg(not(feature = "windows_raw_dylib"))]
 #[link(name = "advapi32")]
 #[link(name = "ntdll")]
 #[link(name = "userenv")]
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 1ddacd92e6b..169eeeca8c2 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -27,3 +27,4 @@ profiler = ["std/profiler"]
 std_detect_file_io = ["std/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
 std_detect_env_override = ["std/std_detect_env_override"]
+windows_raw_dylib = ["std/windows_raw_dylib"]
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index cab37e0da47..3d977bf3058 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -58,9 +58,8 @@ check-aux:
 		library/core \
 		library/alloc \
 		--no-doc
-	# Some doctests have intentional memory leaks.
-	# Some use file system operations to demonstrate dealing with `Result`.
-	$(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \
+	# Some doctests use file system operations to demonstrate dealing with `Result`.
+	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 \
 		library/core \
 		library/alloc \
@@ -70,7 +69,7 @@ check-aux:
 		$(BOOTSTRAP) miri --stage 2 library/std \
 		--no-doc -- \
 		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
-	$(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \
+	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 library/std \
 		--doc -- \
 		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 9b4c7c91349..876ee8be151 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -682,6 +682,8 @@ impl Step for CompiletestTest {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
+            // compiletest uses libtest internals; make it use the in-tree std to make sure it never breaks
+            // when std sources change.
             Mode::ToolStd,
             host,
             "test",
@@ -1321,13 +1323,12 @@ impl Step for CrateRunMakeSupport {
     /// Runs `cargo test` for run-make-support.
     fn run(self, builder: &Builder<'_>) {
         let host = self.host;
-        let compiler = builder.compiler(builder.top_stage, host);
+        let compiler = builder.compiler(0, host);
 
-        builder.ensure(compile::Std::new(compiler, host));
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
-            Mode::ToolStd,
+            Mode::ToolBootstrap,
             host,
             "test",
             "src/tools/run-make-support",