Improve heapapi implementation

This commit is contained in:
Luke Street 2025-10-08 18:11:37 -06:00
parent ce57eb44a8
commit 2ffc56f5c2
3 changed files with 40 additions and 71 deletions

View File

@ -82,6 +82,7 @@ FetchContent_MakeAvailable(mimalloc)
# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1` # Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1`
target_compile_options(mimalloc-obj PRIVATE -Wno-psabi) target_compile_options(mimalloc-obj PRIVATE -Wno-psabi)
target_compile_definitions(mimalloc-obj PRIVATE MI_USE_BUILTIN_THREAD_POINTER=1)
if (WIBO_ENABLE_LIBURING) if (WIBO_ENABLE_LIBURING)
FetchContent_Declare( FetchContent_Declare(

View File

@ -26,7 +26,6 @@ void ensureProcessHeapInitialized() {
if (!record) { if (!record) {
return; return;
} }
record->heap = heap;
record->isProcessHeap = true; record->isProcessHeap = true;
g_processHeapRecord = record.get(); g_processHeapRecord = record.get();
g_processHeapHandle = wibo::handles().alloc(std::move(record), 0, 0); g_processHeapHandle = wibo::handles().alloc(std::move(record), 0, 0);
@ -91,31 +90,23 @@ HANDLE WIN_FUNC HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaxim
} }
auto record = make_pin<HeapObject>(heap); auto record = make_pin<HeapObject>(heap);
record->heap = heap;
record->createFlags = flOptions; record->createFlags = flOptions;
record->initialSize = dwInitialSize; record->initialSize = dwInitialSize;
record->maximumSize = dwMaximumSize; record->maximumSize = dwMaximumSize;
record->isProcessHeap = false; return wibo::handles().alloc(std::move(record), 0, 0);
HANDLE handle = wibo::handles().alloc(std::move(record), 0, 0);
return handle;
} }
BOOL WIN_FUNC HeapDestroy(HANDLE hHeap) { BOOL WIN_FUNC HeapDestroy(HANDLE hHeap) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("HeapDestroy(%p)\n", hHeap); DEBUG_LOG("HeapDestroy(%p)\n", hHeap);
auto record = wibo::handles().getAs<HeapObject>(hHeap); auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) { if (!record || !record->isOwner() || record->isProcessHeap) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
std::lock_guard lk(record->m);
if (record->isProcessHeap || record->heap == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE; wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE; return FALSE;
} }
mi_heap_destroy(record->heap); mi_heap_destroy(record->heap);
record->heap = nullptr; record->heap = nullptr;
wibo::handles().release(hHeap);
return TRUE; return TRUE;
} }
@ -132,15 +123,10 @@ BOOL WIN_FUNC HeapSetInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapI
DEBUG_LOG("HeapSetInformation(%p, %d, %p, %zu)\n", HeapHandle, static_cast<int>(HeapInformationClass), DEBUG_LOG("HeapSetInformation(%p, %d, %p, %zu)\n", HeapHandle, static_cast<int>(HeapInformationClass),
HeapInformation, HeapInformationLength); HeapInformation, HeapInformationLength);
auto record = wibo::handles().getAs<HeapObject>(HeapHandle); auto record = wibo::handles().getAs<HeapObject>(HeapHandle);
if (!record) { if (!record || !record->canAccess()) {
wibo::lastError = ERROR_INVALID_HANDLE; wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE; return FALSE;
} }
std::lock_guard lk(record->m);
if (!record->heap) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
switch (HeapInformationClass) { switch (HeapInformationClass) {
case HeapCompatibilityInformation: { case HeapCompatibilityInformation: {
if (!HeapInformation || HeapInformationLength < sizeof(ULONG)) { if (!HeapInformation || HeapInformationLength < sizeof(ULONG)) {
@ -163,51 +149,39 @@ BOOL WIN_FUNC HeapSetInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapI
LPVOID WIN_FUNC HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) { LPVOID WIN_FUNC HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("HeapAlloc(%p, 0x%x, %zu) ", hHeap, dwFlags, dwBytes); VERBOSE_LOG("HeapAlloc(%p, 0x%x, %zu) ", hHeap, dwFlags, dwBytes);
auto record = wibo::handles().getAs<HeapObject>(hHeap); auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) { if (!record || !record->canAccess()) {
DEBUG_LOG("-> NULL\n"); VERBOSE_LOG("-> NULL\n");
wibo::lastError = ERROR_INVALID_HANDLE; wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr; return nullptr;
} }
std::lock_guard lk(record->m);
if (!record->heap) {
DEBUG_LOG("-> NULL\n");
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
void *mem = heapAllocFromRecord(record.get(), dwFlags, dwBytes); void *mem = heapAllocFromRecord(record.get(), dwFlags, dwBytes);
DEBUG_LOG("-> %p\n", mem); VERBOSE_LOG("-> %p\n", mem);
return mem; return mem;
} }
LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) { LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("HeapReAlloc(%p, 0x%x, %p, %zu) ", hHeap, dwFlags, lpMem, dwBytes); VERBOSE_LOG("HeapReAlloc(%p, 0x%x, %p, %zu) ", hHeap, dwFlags, lpMem, dwBytes);
auto record = wibo::handles().getAs<HeapObject>(hHeap); auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) { if (!record || !record->canAccess()) {
DEBUG_LOG("-> NULL\n"); VERBOSE_LOG("-> NULL\n");
wibo::lastError = ERROR_INVALID_HANDLE; wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr; return nullptr;
} }
std::lock_guard lk(record->m);
if (!record->heap) {
DEBUG_LOG("-> NULL\n");
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
if (lpMem == nullptr) { if (lpMem == nullptr) {
void *alloc = heapAllocFromRecord(record.get(), dwFlags, dwBytes); void *alloc = heapAllocFromRecord(record.get(), dwFlags, dwBytes);
DEBUG_LOG("-> %p (alloc)\n", alloc); VERBOSE_LOG("-> %p (alloc)\n", alloc);
return alloc; return alloc;
} }
// if (!mi_heap_check_owned(record->heap, lpMem)) { if (!mi_heap_check_owned(record->heap, lpMem)) {
// DEBUG_LOG("-> NULL (not owned)\n"); VERBOSE_LOG("-> NULL (not owned)\n");
// wibo::lastError = ERROR_INVALID_PARAMETER; wibo::lastError = ERROR_INVALID_PARAMETER;
// return nullptr; return nullptr;
// } }
if ((record->createFlags | dwFlags) & HEAP_GENERATE_EXCEPTIONS) { if ((record->createFlags | dwFlags) & HEAP_GENERATE_EXCEPTIONS) {
DEBUG_LOG("-> NULL (exceptions unsupported)\n"); VERBOSE_LOG("-> NULL (exceptions unsupported)\n");
wibo::lastError = ERROR_NOT_SUPPORTED; wibo::lastError = ERROR_NOT_SUPPORTED;
return nullptr; return nullptr;
} }
@ -216,10 +190,10 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
if (dwBytes == 0) { if (dwBytes == 0) {
if (!inplaceOnly) { if (!inplaceOnly) {
mi_free(lpMem); mi_free(lpMem);
DEBUG_LOG("-> NULL (freed)\n"); VERBOSE_LOG("-> NULL (freed)\n");
return nullptr; return nullptr;
} }
DEBUG_LOG("-> NULL (zero size with in-place flag)\n"); VERBOSE_LOG("-> NULL (zero size with in-place flag)\n");
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY; wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
return nullptr; return nullptr;
} }
@ -228,11 +202,11 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
const SIZE_T oldSize = mi_usable_size(lpMem); const SIZE_T oldSize = mi_usable_size(lpMem);
if (inplaceOnly || requestSize <= oldSize) { if (inplaceOnly || requestSize <= oldSize) {
if (requestSize > oldSize) { if (requestSize > oldSize) {
DEBUG_LOG("-> NULL (cannot grow in place)\n"); VERBOSE_LOG("-> NULL (cannot grow in place)\n");
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY; wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
return nullptr; return nullptr;
} }
DEBUG_LOG("-> %p (in-place)\n", lpMem); VERBOSE_LOG("-> %p (in-place)\n", lpMem);
return lpMem; return lpMem;
} }
@ -251,30 +225,27 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
if (isExecutableHeap(record.get())) { if (isExecutableHeap(record.get())) {
tryMarkExecutable(ret); tryMarkExecutable(ret);
} }
DEBUG_LOG("-> %p\n", ret); VERBOSE_LOG("-> %p\n", ret);
return ret; return ret;
} }
SIZE_T WIN_FUNC HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) { SIZE_T WIN_FUNC HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("HeapSize(%p, 0x%x, %p)\n", hHeap, dwFlags, lpMem); VERBOSE_LOG("HeapSize(%p, 0x%x, %p)\n", hHeap, dwFlags, lpMem);
(void)dwFlags; (void)dwFlags;
auto record = wibo::handles().getAs<HeapObject>(hHeap); auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) { if (!record || !record->canAccess()) {
VERBOSE_LOG("-> ERROR_INVALID_HANDLE\n");
wibo::lastError = ERROR_INVALID_HANDLE; wibo::lastError = ERROR_INVALID_HANDLE;
return static_cast<SIZE_T>(-1); return static_cast<SIZE_T>(-1);
} }
std::lock_guard lk(record->m);
if (!record->heap) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return static_cast<SIZE_T>(-1);
}
if (!lpMem) { if (!lpMem) {
VERBOSE_LOG("-> ERROR_INVALID_PARAMETER\n");
wibo::lastError = ERROR_INVALID_PARAMETER; wibo::lastError = ERROR_INVALID_PARAMETER;
return static_cast<SIZE_T>(-1); return static_cast<SIZE_T>(-1);
} }
if (!mi_heap_check_owned(record->heap, const_cast<LPVOID>(lpMem))) { if (!mi_heap_check_owned(record->heap, lpMem)) {
DEBUG_LOG("HeapSize: block %p not owned by heap %p\n", lpMem, record->heap); VERBOSE_LOG("-> ERROR_INVALID_PARAMETER (not owned)\n");
wibo::lastError = ERROR_INVALID_PARAMETER; wibo::lastError = ERROR_INVALID_PARAMETER;
return static_cast<SIZE_T>(-1); return static_cast<SIZE_T>(-1);
} }
@ -284,30 +255,24 @@ SIZE_T WIN_FUNC HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) {
BOOL WIN_FUNC HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { BOOL WIN_FUNC HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("HeapFree(%p, 0x%x, %p)\n", hHeap, dwFlags, lpMem); VERBOSE_LOG("HeapFree(%p, 0x%x, %p)\n", hHeap, dwFlags, lpMem);
(void)dwFlags; (void)dwFlags;
if (lpMem == nullptr) { if (lpMem == nullptr) {
return TRUE; return TRUE;
} }
auto record = wibo::handles().getAs<HeapObject>(hHeap); auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) { if (!record || !record->canAccess()) {
DEBUG_LOG("-> INVALID_HANDLE\n"); VERBOSE_LOG("-> ERROR_INVALID_HANDLE\n");
wibo::lastError = ERROR_INVALID_HANDLE; wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE; return FALSE;
} }
std::lock_guard lk(record->m);
if (!record->heap) {
DEBUG_LOG("-> INVALID_PARAMETER\n");
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (!mi_heap_check_owned(record->heap, lpMem)) { if (!mi_heap_check_owned(record->heap, lpMem)) {
DEBUG_LOG("-> INVALID_PARAMETER (not owned)\n"); VERBOSE_LOG("-> ERROR_INVALID_PARAMETER (not owned)\n");
wibo::lastError = ERROR_INVALID_PARAMETER; wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE; return FALSE;
} }
mi_free(lpMem); mi_free(lpMem);
DEBUG_LOG("-> SUCCESS\n"); VERBOSE_LOG("-> SUCCESS\n");
return TRUE; return TRUE;
} }

View File

@ -153,16 +153,19 @@ struct SemaphoreObject final : WaitableObject {
struct HeapObject : public ObjectBase { struct HeapObject : public ObjectBase {
static constexpr ObjectType kType = ObjectType::Heap; static constexpr ObjectType kType = ObjectType::Heap;
std::mutex m;
mi_heap_t *heap; mi_heap_t *heap;
const pthread_t owner;
DWORD createFlags = 0; DWORD createFlags = 0;
SIZE_T initialSize = 0; SIZE_T initialSize = 0;
SIZE_T maximumSize = 0; SIZE_T maximumSize = 0;
DWORD compatibility = 0; DWORD compatibility = 0;
bool isProcessHeap = false; bool isProcessHeap = false;
explicit HeapObject(mi_heap_t *heap) : ObjectBase(kType), heap(heap) {} explicit HeapObject(mi_heap_t *heap) : ObjectBase(kType), heap(heap), owner(pthread_self()) {}
~HeapObject() override; ~HeapObject() override;
[[nodiscard]] inline bool isOwner() const { return pthread_equal(owner, pthread_self()); }
[[nodiscard]] inline bool canAccess() const { return (isProcessHeap || isOwner()) && heap != nullptr; }
}; };
inline constexpr uintptr_t kPseudoCurrentProcessHandleValue = static_cast<uintptr_t>(-1); inline constexpr uintptr_t kPseudoCurrentProcessHandleValue = static_cast<uintptr_t>(-1);