New handles, threading and processes subsystems

This commit is contained in:
2025-10-04 13:16:25 -06:00
parent 704dfd90ec
commit 390f26b28d
36 changed files with 2023 additions and 1875 deletions

View File

@@ -7,71 +7,36 @@
#include <algorithm>
#include <mimalloc.h>
#include <mutex>
#include <new>
#include <sys/mman.h>
using kernel32::HeapObject;
namespace {
struct HeapRecord {
mi_heap_t *heap = nullptr;
DWORD createFlags = 0;
SIZE_T initialSize = 0;
SIZE_T maximumSize = 0;
DWORD compatibility = 0;
bool isProcessHeap = false;
};
std::once_flag g_processHeapInitFlag;
HANDLE g_processHeapHandle = nullptr;
HeapRecord *g_processHeapRecord = nullptr;
HeapObject *g_processHeapRecord = nullptr;
void ensureProcessHeapInitialized() {
std::call_once(g_processHeapInitFlag, []() {
mi_heap_t *heap = mi_heap_get_default();
auto *record = new (std::nothrow) HeapRecord{};
auto record = make_pin<HeapObject>(heap);
if (!record) {
return;
}
record->heap = heap;
record->isProcessHeap = true;
g_processHeapRecord = record;
g_processHeapHandle = handles::allocDataHandle({handles::TYPE_HEAP, record, 0});
g_processHeapRecord = record.get();
g_processHeapHandle = wibo::handles().alloc(std::move(record), 0, 0);
});
}
HeapRecord *activeHeapRecord(HANDLE hHeap) {
if (!hHeap) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
ensureProcessHeapInitialized();
auto data = handles::dataFromHandle(hHeap, false);
if (data.type != handles::TYPE_HEAP || data.ptr == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
wibo::lastError = ERROR_SUCCESS;
return static_cast<HeapRecord *>(data.ptr);
}
HeapRecord *popHeapRecord(HANDLE hHeap) {
ensureProcessHeapInitialized();
auto preview = handles::dataFromHandle(hHeap, false);
if (preview.type != handles::TYPE_HEAP || preview.ptr == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
auto data = handles::dataFromHandle(hHeap, true);
wibo::lastError = ERROR_SUCCESS;
return static_cast<HeapRecord *>(data.ptr);
}
bool isExecutableHeap(const HeapRecord *record) {
bool isExecutableHeap(const HeapObject *record) {
return record && ((record->createFlags & HEAP_CREATE_ENABLE_EXECUTE) != 0);
}
LPVOID heapAllocFromRecord(HeapRecord *record, DWORD dwFlags, SIZE_T dwBytes) {
if (!record) {
LPVOID heapAllocFromRecord(HeapObject *record, DWORD dwFlags, SIZE_T dwBytes) {
if (!record || !record->heap) {
return nullptr;
}
if ((record->createFlags | dwFlags) & HEAP_GENERATE_EXCEPTIONS) {
@@ -95,6 +60,19 @@ LPVOID heapAllocFromRecord(HeapRecord *record, DWORD dwFlags, SIZE_T dwBytes) {
} // namespace
HeapObject::~HeapObject() {
if (heap) {
if (!isProcessHeap) {
mi_heap_destroy(heap);
}
heap = nullptr;
}
if (isProcessHeap) {
g_processHeapHandle = nullptr;
g_processHeapRecord = nullptr;
}
}
namespace kernel32 {
HANDLE WIN_FUNC HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) {
@@ -110,40 +88,32 @@ HANDLE WIN_FUNC HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaxim
return nullptr;
}
auto *record = new (std::nothrow) HeapRecord{};
if (!record) {
mi_heap_delete(heap);
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
return nullptr;
}
auto record = make_pin<HeapObject>(heap);
record->heap = heap;
record->createFlags = flOptions;
record->initialSize = dwInitialSize;
record->maximumSize = dwMaximumSize;
record->isProcessHeap = false;
HANDLE handle = handles::allocDataHandle({handles::TYPE_HEAP, record, 0});
HANDLE handle = wibo::handles().alloc(std::move(record), 0, 0);
wibo::lastError = ERROR_SUCCESS;
return handle;
}
BOOL WIN_FUNC HeapDestroy(HANDLE hHeap) {
DEBUG_LOG("HeapDestroy(%p)\n", hHeap);
HeapRecord *record = activeHeapRecord(hHeap);
auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
if (record->isProcessHeap) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
record = popHeapRecord(hHeap);
if (!record) {
std::lock_guard lk(record->m);
if (record->isProcessHeap || record->heap == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
mi_heap_destroy(record->heap);
delete record;
record->heap = nullptr;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
@@ -159,18 +129,23 @@ BOOL WIN_FUNC HeapSetInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapI
SIZE_T HeapInformationLength) {
DEBUG_LOG("HeapSetInformation(%p, %d, %p, %zu)\n", HeapHandle, static_cast<int>(HeapInformationClass),
HeapInformation, HeapInformationLength);
ensureProcessHeapInitialized();
auto record = wibo::handles().getAs<HeapObject>(HeapHandle);
if (!record) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
std::lock_guard lk(record->m);
if (!record->heap) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
switch (HeapInformationClass) {
case HeapCompatibilityInformation: {
if (!HeapInformation || HeapInformationLength < sizeof(ULONG)) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
HeapRecord *target = HeapHandle ? activeHeapRecord(HeapHandle) : g_processHeapRecord;
if (!target) {
return FALSE;
}
target->compatibility = *static_cast<ULONG *>(HeapInformation);
record->compatibility = *static_cast<ULONG *>(HeapInformation);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
@@ -188,36 +163,51 @@ BOOL WIN_FUNC HeapSetInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapI
LPVOID WIN_FUNC HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) {
DEBUG_LOG("HeapAlloc(%p, 0x%x, %zu) ", hHeap, dwFlags, dwBytes);
HeapRecord *record = activeHeapRecord(hHeap);
auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) {
DEBUG_LOG("-> NULL\n");
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
void *mem = heapAllocFromRecord(record, dwFlags, dwBytes);
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);
DEBUG_LOG("-> %p\n", mem);
return mem;
}
LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) {
DEBUG_LOG("HeapReAlloc(%p, 0x%x, %p, %zu) ", hHeap, dwFlags, lpMem, dwBytes);
HeapRecord *record = activeHeapRecord(hHeap);
auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) {
DEBUG_LOG("-> NULL\n");
wibo::lastError = ERROR_INVALID_HANDLE;
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) {
void *alloc = heapAllocFromRecord(record, dwFlags, dwBytes);
void *alloc = heapAllocFromRecord(record.get(), dwFlags, dwBytes);
DEBUG_LOG("-> %p (alloc)\n", alloc);
wibo::lastError = ERROR_SUCCESS;
return alloc;
}
if (!mi_heap_check_owned(record->heap, lpMem)) {
wibo::lastError = ERROR_INVALID_PARAMETER;
DEBUG_LOG("-> NULL (not owned)\n");
return nullptr;
}
// if (!mi_heap_check_owned(record->heap, lpMem)) {
// DEBUG_LOG("-> NULL (not owned)\n");
// wibo::lastError = ERROR_INVALID_PARAMETER;
// return nullptr;
// }
if ((record->createFlags | dwFlags) & HEAP_GENERATE_EXCEPTIONS) {
DEBUG_LOG("-> NULL (exceptions unsupported)\n");
wibo::lastError = ERROR_INVALID_PARAMETER;
wibo::lastError = ERROR_NOT_SUPPORTED;
return nullptr;
}
const bool inplaceOnly = (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) != 0;
@@ -225,12 +215,12 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
if (dwBytes == 0) {
if (!inplaceOnly) {
mi_free(lpMem);
wibo::lastError = ERROR_SUCCESS;
DEBUG_LOG("-> NULL (freed)\n");
wibo::lastError = ERROR_SUCCESS;
return nullptr;
}
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
DEBUG_LOG("-> NULL (zero size with in-place flag)\n");
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
return nullptr;
}
@@ -238,12 +228,12 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
const SIZE_T oldSize = mi_usable_size(lpMem);
if (inplaceOnly || requestSize <= oldSize) {
if (requestSize > oldSize) {
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
DEBUG_LOG("-> NULL (cannot grow in place)\n");
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
return nullptr;
}
wibo::lastError = ERROR_SUCCESS;
DEBUG_LOG("-> %p (in-place)\n", lpMem);
wibo::lastError = ERROR_SUCCESS;
return lpMem;
}
@@ -259,7 +249,7 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
memset(static_cast<char *>(ret) + oldSize, 0, zeroLen);
}
}
if (isExecutableHeap(record)) {
if (isExecutableHeap(record.get())) {
tryMarkExecutable(ret);
}
wibo::lastError = ERROR_SUCCESS;
@@ -270,18 +260,24 @@ LPVOID WIN_FUNC HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dw
SIZE_T WIN_FUNC HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) {
DEBUG_LOG("HeapSize(%p, 0x%x, %p)\n", hHeap, dwFlags, lpMem);
(void)dwFlags;
HeapRecord *record = activeHeapRecord(hHeap);
auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) {
wibo::lastError = ERROR_INVALID_HANDLE;
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) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return static_cast<SIZE_T>(-1);
}
if (!mi_heap_check_owned(record->heap, const_cast<LPVOID>(lpMem))) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return static_cast<SIZE_T>(-1);
}
// if (!mi_heap_check_owned(record->heap, const_cast<LPVOID>(lpMem))) {
// wibo::lastError = ERROR_INVALID_PARAMETER;
// return static_cast<SIZE_T>(-1);
// }
size_t size = mi_usable_size(lpMem);
wibo::lastError = ERROR_SUCCESS;
return static_cast<SIZE_T>(size);
@@ -294,15 +290,24 @@ BOOL WIN_FUNC HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
HeapRecord *record = activeHeapRecord(hHeap);
auto record = wibo::handles().getAs<HeapObject>(hHeap);
if (!record) {
DEBUG_LOG("-> INVALID_HANDLE\n");
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
if (!mi_heap_check_owned(record->heap, lpMem)) {
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)) {
// wibo::lastError = ERROR_INVALID_PARAMETER;
// return FALSE;
// }
mi_free(lpMem);
DEBUG_LOG("-> SUCCESS\n");
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}