Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert using HEAP static in Windows alloc #131888

Merged
merged 1 commit into from
Nov 7, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 12 additions & 57 deletions library/std/src/sys/alloc/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::alloc::{GlobalAlloc, Layout, System};
use crate::ffi::c_void;
use crate::mem::MaybeUninit;
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering};
use crate::sys::c;

#[cfg(test)]
Expand Down Expand Up @@ -81,69 +80,25 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
// 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 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.
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 {
// `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()
}
fn get_process_heap() -> *mut c_void {
// SAFETY: GetProcessHeap simply returns a valid handle or NULL so is always safe to call.
unsafe { GetProcessHeap() }
}

/// This is outlined from `process_heap_alloc` so that `process_heap_alloc`
/// does not need any stack allocations.
#[inline(never)]
#[cold]
extern "C" fn process_heap_init_and_alloc(
_heap: MaybeUninit<c::HANDLE>, // We pass this argument to match the ABI of `HeapAlloc`
fn process_heap_alloc(
_heap: MaybeUninit<c::HANDLE>, // We pass this argument to match the ABI of `HeapAlloc`,
flags: u32,
bytes: usize,
) -> *mut c_void {
let heap = init_or_get_process_heap();
let heap = get_process_heap();
if core::intrinsics::unlikely(heap.is_null()) {
return ptr::null_mut();
}
// SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`.
unsafe { HeapAlloc(heap, flags, bytes) }
}

#[inline(never)]
fn process_heap_alloc(
_heap: MaybeUninit<c::HANDLE>, // We pass this argument to match the ABI of `HeapAlloc`,
flags: u32,
bytes: usize,
) -> *mut c_void {
let heap = HEAP.load(Ordering::Relaxed);
if core::intrinsics::likely(!heap.is_null()) {
// SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`.
unsafe { HeapAlloc(heap, flags, bytes) }
} else {
process_heap_init_and_alloc(MaybeUninit::uninit(), flags, bytes)
}
}

// Get a non-null handle to the default heap of the current process.
// SAFETY: `HEAP` must have been successfully initialized.
#[inline]
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)]
Expand Down Expand Up @@ -232,9 +187,9 @@ unsafe impl GlobalAlloc for System {
}
};

// SAFETY: because `ptr` has been successfully allocated with this allocator,
// `HEAP` must have been successfully initialized.
let heap = unsafe { get_process_heap() };
// because `ptr` has been successfully allocated with this allocator,
// there must be a valid process heap.
let heap = get_process_heap();

// SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`,
// `block` is a pointer to the start of an allocated block.
Expand All @@ -244,9 +199,9 @@ unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN {
// SAFETY: because `ptr` has been successfully allocated with this allocator,
// `HEAP` must have been successfully initialized.
let heap = unsafe { get_process_heap() };
// because `ptr` has been successfully allocated with this allocator,
// there must be a valid process heap.
let heap = get_process_heap();

// SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`,
// `ptr` is a pointer to the start of an allocated block.
Expand Down
Loading