about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/ffi/os_str.rs4
-rw-r--r--library/std/src/io/mod.rs6
-rw-r--r--library/std/src/keyword_docs.rs27
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/path.rs14
-rw-r--r--library/std/src/prelude/mod.rs64
-rw-r--r--library/std/src/sync/once.rs2
-rw-r--r--library/std/src/sys/windows/alloc.rs237
-rw-r--r--library/std/src/sys/windows/alloc/tests.rs9
-rw-r--r--library/std/src/sys/windows/c.rs7
10 files changed, 285 insertions, 88 deletions
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 14914287cb1..ecaab670349 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -361,7 +361,7 @@ impl OsString {
 impl From<String> for OsString {
     /// Converts a [`String`] into a [`OsString`].
     ///
-    /// The conversion copies the data, and includes an allocation on the heap.
+    /// This conversion does not allocate or copy memory.
     #[inline]
     fn from(s: String) -> OsString {
         OsString { inner: Buf::from_string(s) }
@@ -858,7 +858,7 @@ impl From<Cow<'_, OsStr>> for Box<OsStr> {
 
 #[stable(feature = "os_string_from_box", since = "1.18.0")]
 impl From<Box<OsStr>> for OsString {
-    /// Converts a [`Box`]`<`[`OsStr`]`>` into a `OsString` without copying or
+    /// Converts a [`Box`]`<`[`OsStr`]`>` into an [`OsString`] without copying or
     /// allocating.
     #[inline]
     fn from(boxed: Box<OsStr>) -> OsString {
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 9953bcd556d..9625984195b 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -505,7 +505,8 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
 /// [`std::io`]: self
 /// [`File`]: crate::fs::File
 #[stable(feature = "rust1", since = "1.0.0")]
-#[doc(spotlight)]
+#[cfg_attr(bootstrap, doc(spotlight))]
+#[cfg_attr(not(bootstrap), doc(notable_trait))]
 pub trait Read {
     /// Pull some bytes from this source into the specified buffer, returning
     /// how many bytes were read.
@@ -1296,7 +1297,8 @@ impl Initializer {
 ///
 /// [`write_all`]: Write::write_all
 #[stable(feature = "rust1", since = "1.0.0")]
-#[doc(spotlight)]
+#[cfg_attr(bootstrap, doc(spotlight))]
+#[cfg_attr(not(bootstrap), doc(notable_trait))]
 pub trait Write {
     /// Write a buffer into this writer, returning how many bytes were written.
     ///
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index e64cbc18bf7..2a3d44fb17d 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -547,15 +547,18 @@ mod fn_keyword {}
 /// # fn code() { }
 /// # let iterator = 0..2;
 /// {
-///     let mut _iter = std::iter::IntoIterator::into_iter(iterator);
-///     loop {
-///         match _iter.next() {
-///             Some(loop_variable) => {
-///                 code()
-///             },
-///             None => break,
-///         }
-///     }
+///     let result = match IntoIterator::into_iter(iterator) {
+///         mut iter => loop {
+///             let next;
+///             match iter.next() {
+///                 Some(val) => next = val,
+///                 None => break,
+///             };
+///             let loop_variable = next;
+///             let () = { code(); };
+///         },
+///     };
+///     result
 /// }
 /// ```
 ///
@@ -1310,7 +1313,11 @@ mod return_keyword {}
 /// [Reference]: ../reference/items/associated-items.html#methods
 mod self_keyword {}
 
-#[doc(keyword = "Self")]
+// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can remove the
+// three next lines and put back: `#[doc(keyword = "Self")]`.
+#[doc(alias = "Self")]
+#[allow(rustc::existing_doc_keyword)]
+#[doc(keyword = "SelfTy")]
 //
 /// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type
 /// definition.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 3719eeb1840..d5ba2d36346 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -257,7 +257,8 @@
 #![feature(doc_cfg)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
-#![feature(doc_spotlight)]
+#![cfg_attr(bootstrap, feature(doc_spotlight))]
+#![cfg_attr(not(bootstrap), feature(doc_notable_trait))]
 #![feature(dropck_eyepatch)]
 #![feature(duration_constants)]
 #![feature(duration_zero)]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 57c892f32b1..f4020a42879 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1467,7 +1467,7 @@ impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<OsString> for PathBuf {
-    /// Converts a `OsString` into a `PathBuf`
+    /// Converts an [`OsString`] into a [`PathBuf`]
     ///
     /// This conversion does not allocate or copy memory.
     #[inline]
@@ -1478,7 +1478,7 @@ impl From<OsString> for PathBuf {
 
 #[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")]
 impl From<PathBuf> for OsString {
-    /// Converts a `PathBuf` into a `OsString`
+    /// Converts a [`PathBuf`] into an [`OsString`]
     ///
     /// This conversion does not allocate or copy memory.
     #[inline]
@@ -1489,7 +1489,7 @@ impl From<PathBuf> for OsString {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<String> for PathBuf {
-    /// Converts a `String` into a `PathBuf`
+    /// Converts a [`String`] into a [`PathBuf`]
     ///
     /// This conversion does not allocate or copy memory.
     #[inline]
@@ -1595,7 +1595,7 @@ impl<'a> From<Cow<'a, Path>> for PathBuf {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<PathBuf> for Arc<Path> {
-    /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer.
+    /// Converts a [`PathBuf`] into an [`Arc`] by moving the [`PathBuf`] data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: PathBuf) -> Arc<Path> {
         let arc: Arc<OsStr> = Arc::from(s.into_os_string());
@@ -1605,7 +1605,7 @@ impl From<PathBuf> for Arc<Path> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&Path> for Arc<Path> {
-    /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer.
+    /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: &Path) -> Arc<Path> {
         let arc: Arc<OsStr> = Arc::from(s.as_os_str());
@@ -1615,7 +1615,7 @@ impl From<&Path> for Arc<Path> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<PathBuf> for Rc<Path> {
-    /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer.
+    /// Converts a [`PathBuf`] into an [`Rc`] by moving the [`PathBuf`] data into a new `Rc` buffer.
     #[inline]
     fn from(s: PathBuf) -> Rc<Path> {
         let rc: Rc<OsStr> = Rc::from(s.into_os_string());
@@ -1625,7 +1625,7 @@ impl From<PathBuf> for Rc<Path> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&Path> for Rc<Path> {
-    /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer.
+    /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new `Rc` buffer.
     #[inline]
     fn from(s: &Path) -> Rc<Path> {
         let rc: Rc<OsStr> = Rc::from(s.as_os_str());
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index 505b5f3013b..1b4facdd049 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -28,53 +28,53 @@
 //! The current version of the prelude (version 1) lives in
 //! [`std::prelude::v1`], and re-exports the following:
 //!
-//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}:
+//! * <code>[std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}</code>,
 //!   marker traits that indicate fundamental properties of types.
-//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}: various
+//! * <code>[std::ops]::{[Drop], [Fn], [FnMut], [FnOnce]}</code>, various
 //!   operations for both destructors and overloading `()`.
-//! * [`std::mem`]::[`drop`][`mem::drop`]: a convenience function for explicitly
+//! * <code>[std::mem]::[drop][mem::drop]</code>, a convenience function for explicitly
 //!   dropping a value.
-//! * [`std::boxed`]::[`Box`]: a way to allocate values on the heap.
-//! * [`std::borrow`]::[`ToOwned`]: the conversion trait that defines
+//! * <code>[std::boxed]::[Box]</code>, a way to allocate values on the heap.
+//! * <code>[std::borrow]::[ToOwned]</code>, the conversion trait that defines
 //!   [`to_owned`], the generic method for creating an owned type from a
 //!   borrowed type.
-//! * [`std::clone`]::[`Clone`]: the ubiquitous trait that defines
-//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
-//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`]}: the
+//! * <code>[std::clone]::[Clone]</code>, the ubiquitous trait that defines
+//!   [`clone`][Clone::clone], the method for producing a copy of a value.
+//! * <code>[std::cmp]::{[PartialEq], [PartialOrd], [Eq], [Ord]}</code>, the
 //!   comparison traits, which implement the comparison operators and are often
 //!   seen in trait bounds.
-//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}: generic
+//! * <code>[std::convert]::{[AsRef], [AsMut], [Into], [From]}</code>, generic
 //!   conversions, used by savvy API authors to create overloaded methods.
-//! * [`std::default`]::[`Default`], types that have default values.
-//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
-//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}: iterators of various
+//! * <code>[std::default]::[Default]</code>, types that have default values.
+//! * <code>[std::iter]::{[Iterator], [Extend], [IntoIterator], [DoubleEndedIterator], [ExactSizeIterator]}</code>,
+//!   iterators of various
 //!   kinds.
-//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}, a
+//! * <code>[std::option]::[Option]::{[self][Option], [Some], [None]}</code>, a
 //!   type which expresses the presence or absence of a value. This type is so
 //!   commonly used, its variants are also exported.
-//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}: a type
+//! * <code>[std::result]::[Result]::{[self][Result], [Ok], [Err]}</code>, a type
 //!   for functions that may succeed or fail. Like [`Option`], its variants are
 //!   exported as well.
-//! * [`std::string`]::{[`String`], [`ToString`]}: heap-allocated strings.
-//! * [`std::vec`]::[`Vec`]: a growable, heap-allocated vector.
+//! * <code>[std::string]::{[String], [ToString]}</code>, heap-allocated strings.
+//! * <code>[std::vec]::[Vec]</code>, a growable, heap-allocated vector.
 //!
-//! [`mem::drop`]: crate::mem::drop
-//! [`std::borrow`]: crate::borrow
-//! [`std::boxed`]: crate::boxed
-//! [`std::clone`]: crate::clone
-//! [`std::cmp`]: crate::cmp
-//! [`std::convert`]: crate::convert
-//! [`std::default`]: crate::default
-//! [`std::iter`]: crate::iter
-//! [`std::marker`]: crate::marker
-//! [`std::mem`]: crate::mem
-//! [`std::ops`]: crate::ops
-//! [`std::option`]: crate::option
+//! [mem::drop]: crate::mem::drop
+//! [std::borrow]: crate::borrow
+//! [std::boxed]: crate::boxed
+//! [std::clone]: crate::clone
+//! [std::cmp]: crate::cmp
+//! [std::convert]: crate::convert
+//! [std::default]: crate::default
+//! [std::iter]: crate::iter
+//! [std::marker]: crate::marker
+//! [std::mem]: crate::mem
+//! [std::ops]: crate::ops
+//! [std::option]: crate::option
 //! [`std::prelude::v1`]: v1
-//! [`std::result`]: crate::result
-//! [`std::slice`]: crate::slice
-//! [`std::string`]: crate::string
-//! [`std::vec`]: mod@crate::vec
+//! [std::result]: crate::result
+//! [std::slice]: crate::slice
+//! [std::string]: crate::string
+//! [std::vec]: mod@crate::vec
 //! [`to_owned`]: crate::borrow::ToOwned::to_owned
 //! [book-closures]: ../../book/ch13-01-closures.html
 //! [book-dtor]: ../../book/ch15-03-drop.html
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 2e5f843fc43..a24a5cb2ae3 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -471,7 +471,7 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) {
             // If the managing thread happens to signal and unpark us before we
             // can park ourselves, the result could be this thread never gets
             // unparked. Luckily `park` comes with the guarantee that if it got
-            // an `unpark` just before on an unparked thread is does not park.
+            // an `unpark` just before on an unparked thread it does not park.
             thread::park();
         }
         break;
diff --git a/library/std/src/sys/windows/alloc.rs b/library/std/src/sys/windows/alloc.rs
index 99b4d6c72a0..af93cd7a3e2 100644
--- a/library/std/src/sys/windows/alloc.rs
+++ b/library/std/src/sys/windows/alloc.rs
@@ -1,61 +1,246 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
 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_common::alloc::{realloc_fallback, MIN_ALIGN};
 
-#[repr(C)]
-struct Header(*mut u8);
+#[cfg(test)]
+mod tests;
+
+// Heap memory management on Windows is done by using the system Heap API (heapapi.h)
+// See https://docs.microsoft.com/windows/win32/api/heapapi/
+
+// Flag to indicate that the memory returned by `HeapAlloc` should be zeroed.
+const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008;
 
-unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
-    &mut *(ptr as *mut Header).offset(-1)
+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;
+
+    // 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;
+
+    // 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;
+
+    // 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;
 }
 
-unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
-    let aligned = ptr.add(align - (ptr as usize & (align - 1)));
-    *get_header(aligned) = Header(ptr);
-    aligned
+// 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.
+static HEAP: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
+
+// Get a handle to the default heap of the current process, or null if the operation fails.
+// If this operation is successful, `HEAP` will be successfully initialized and contain
+// a non-null handle returned by `GetProcessHeap`.
+#[inline]
+fn init_or_get_process_heap() -> c::HANDLE {
+    let heap = HEAP.load(Ordering::Relaxed);
+    if heap.is_null() {
+        // `HEAP` has not yet been successfully initialized
+        let heap = unsafe { GetProcessHeap() };
+        if !heap.is_null() {
+            // SAFETY: No locking is needed because within the same process,
+            // successful calls to `GetProcessHeap` will always return the same value, even on different threads.
+            HEAP.store(heap, Ordering::Release);
+
+            // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap`
+            heap
+        } else {
+            // Could not get the current process heap.
+            ptr::null_mut()
+        }
+    } else {
+        // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap`
+        heap
+    }
 }
 
+// Get a non-null handle to the default heap of the current process.
+// SAFETY: `HEAP` must have been successfully initialized.
 #[inline]
-unsafe fn allocate_with_flags(layout: Layout, flags: c::DWORD) -> *mut u8 {
-    if layout.align() <= MIN_ALIGN {
-        return c::HeapAlloc(c::GetProcessHeap(), flags, layout.size()) as *mut u8;
+unsafe fn get_process_heap() -> c::HANDLE {
+    HEAP.load(Ordering::Acquire)
+}
+
+// Header containing a pointer to the start of an allocated block.
+// SAFETY: Size and alignment must be <= `MIN_ALIGN`.
+#[repr(C)]
+struct Header(*mut u8);
+
+// Allocate a block of optionally zeroed memory for a given `layout`.
+// SAFETY: Returns a pointer satisfying the guarantees of `System` about allocated pointers,
+// or null if the operation fails. If this returns non-null `HEAP` will have been successfully
+// initialized.
+#[inline]
+unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 {
+    let heap = init_or_get_process_heap();
+    if heap.is_null() {
+        // Allocation has failed, could not get the current process heap.
+        return ptr::null_mut();
     }
 
-    let size = layout.size() + layout.align();
-    let ptr = c::HeapAlloc(c::GetProcessHeap(), flags, size);
-    if ptr.is_null() { ptr as *mut u8 } else { align_ptr(ptr as *mut u8, layout.align()) }
+    // Allocated memory will be either zeroed or uninitialized.
+    let flags = if zeroed { HEAP_ZERO_MEMORY } else { 0 };
+
+    if layout.align() <= MIN_ALIGN {
+        // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`.
+        // The returned pointer points to the start of an allocated block.
+        unsafe { HeapAlloc(heap, flags, layout.size()) as *mut u8 }
+    } else {
+        // Allocate extra padding in order to be able to satisfy the alignment.
+        let total = layout.align() + layout.size();
+
+        // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`.
+        let ptr = unsafe { HeapAlloc(heap, flags, total) as *mut u8 };
+        if ptr.is_null() {
+            // Allocation has failed.
+            return ptr::null_mut();
+        }
+
+        // Create a correctly aligned pointer offset from the start of the allocated block,
+        // and write a header before it.
+
+        let offset = layout.align() - (ptr as usize & (layout.align() - 1));
+        // SAFETY: `MIN_ALIGN` <= `offset` <= `layout.align()` and the size of the allocated
+        // block is `layout.align() + layout.size()`. `aligned` will thus be a correctly aligned
+        // pointer inside the allocated block with at least `layout.size()` bytes after it and at
+        // least `MIN_ALIGN` bytes of padding before it.
+        let aligned = unsafe { ptr.add(offset) };
+        // SAFETY: Because the size and alignment of a header is <= `MIN_ALIGN` and `aligned`
+        // is aligned to at least `MIN_ALIGN` and has at least `MIN_ALIGN` bytes of padding before
+        // it, it is safe to write a header directly before it.
+        unsafe { ptr::write((aligned as *mut Header).offset(-1), Header(ptr)) };
+
+        // SAFETY: The returned pointer does not point to the to the start of an allocated block,
+        // but there is a header readable directly before it containing the location of the start
+        // of the block.
+        aligned
+    }
 }
 
+// All pointers returned by this allocator have, in addition to the guarantees of `GlobalAlloc`, the
+// following properties:
+//
+// If the pointer was allocated or reallocated with a `layout` specifying an alignment <= `MIN_ALIGN`
+// the pointer will be aligned to at least `MIN_ALIGN` and point to the start of the allocated block.
+//
+// If the pointer was allocated or reallocated with a `layout` specifying an alignment > `MIN_ALIGN`
+// the pointer will be aligned to the specified alignment and not point to the start of the allocated block.
+// Instead there will be a header readable directly before the returned pointer, containing the actual
+// location of the start of the block.
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        allocate_with_flags(layout, 0)
+        // SAFETY: Pointers returned by `allocate` satisfy the guarantees of `System`
+        let zeroed = false;
+        unsafe { allocate(layout, zeroed) }
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        allocate_with_flags(layout, c::HEAP_ZERO_MEMORY)
+        // SAFETY: Pointers returned by `allocate` satisfy the guarantees of `System`
+        let zeroed = true;
+        unsafe { allocate(layout, zeroed) }
     }
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        if layout.align() <= MIN_ALIGN {
-            let err = c::HeapFree(c::GetProcessHeap(), 0, ptr as c::LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", c::GetLastError());
-        } else {
-            let header = get_header(ptr);
-            let err = c::HeapFree(c::GetProcessHeap(), 0, header.0 as c::LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", c::GetLastError());
-        }
+        let block = {
+            if layout.align() <= MIN_ALIGN {
+                ptr
+            } else {
+                // The location of the start of the block is stored in the padding before `ptr`.
+
+                // SAFETY: Because of the contract of `System`, `ptr` is guaranteed to be non-null
+                // and have a header readable directly before it.
+                unsafe { ptr::read((ptr as *mut Header).offset(-1)).0 }
+            }
+        };
+
+        // SAFETY: because `ptr` has been successfully allocated with this allocator,
+        // `HEAP` must have been successfully initialized.
+        let heap = unsafe { get_process_heap() };
+
+        // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`,
+        // `block` is a pointer to the start of an allocated block.
+        unsafe { HeapFree(heap, 0, block as c::LPVOID) };
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
         if layout.align() <= MIN_ALIGN {
-            c::HeapReAlloc(c::GetProcessHeap(), 0, ptr as c::LPVOID, new_size) as *mut u8
+            // SAFETY: because `ptr` has been successfully allocated with this allocator,
+            // `HEAP` must have been successfully initialized.
+            let heap = unsafe { get_process_heap() };
+
+            // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`,
+            // `ptr` is a pointer to the start of an allocated block.
+            // The returned pointer points to the start of an allocated block.
+            unsafe { HeapReAlloc(heap, 0, ptr as c::LPVOID, new_size) as *mut u8 }
         } else {
-            realloc_fallback(self, ptr, layout, new_size)
+            // SAFETY: `realloc_fallback` is implemented using `dealloc` and `alloc`, which will
+            // correctly handle `ptr` and return a pointer satisfying the guarantees of `System`
+            unsafe { realloc_fallback(self, ptr, layout, new_size) }
         }
     }
 }
diff --git a/library/std/src/sys/windows/alloc/tests.rs b/library/std/src/sys/windows/alloc/tests.rs
new file mode 100644
index 00000000000..674a3e1d92d
--- /dev/null
+++ b/library/std/src/sys/windows/alloc/tests.rs
@@ -0,0 +1,9 @@
+use super::{Header, MIN_ALIGN};
+use crate::mem;
+
+#[test]
+fn alloc_header() {
+    // Header must fit in the padding before an aligned pointer
+    assert!(mem::size_of::<Header>() <= MIN_ALIGN);
+    assert!(mem::align_of::<Header>() <= MIN_ALIGN);
+}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 9789ed085e2..3e4176ef7f8 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -285,8 +285,6 @@ pub const FD_SETSIZE: usize = 64;
 
 pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
 
-pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
-
 pub const STATUS_SUCCESS: NTSTATUS = 0x00000000;
 
 #[repr(C)]
@@ -1017,11 +1015,6 @@ extern "system" {
         timeout: *const timeval,
     ) -> c_int;
 
-    pub fn GetProcessHeap() -> HANDLE;
-    pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
-    pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
-    pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
-
     // >= Vista / Server 2008
     // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
     pub fn CreateSymbolicLinkW(