Skip to content
Open
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
59 changes: 58 additions & 1 deletion src/engine/engine_util_errmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,64 @@
#include <unistd.h>
#endif

#ifdef _WIN32
#include <windows.h>
#endif

#include "engine/engine_array_safety.h"
#include "engine/engine_macro.h"

//------------------------- cross-platform aligned malloc/free -------------------------------------

#ifdef _WIN32

// virtualalloc has 64KB min alloc granularity
#define MJU_LARGE_ALLOC_THRESHOLD (1 << 16)

static LONG CALLBACK mju_commitHandler(EXCEPTION_POINTERS* ep) {
if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
ULONG_PTR access_type = ep->ExceptionRecord->ExceptionInformation[0];
void* fault_addr = (void*)ep->ExceptionRecord->ExceptionInformation[1];
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(fault_addr, &mbi, sizeof(mbi)) != 0) {
// commit just the faulting page
if (mbi.State == MEM_RESERVE) {
if (VirtualAlloc(fault_addr, 1, MEM_COMMIT, PAGE_READWRITE)) {
return EXCEPTION_CONTINUE_EXECUTION;
}
}

if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_READWRITE) && access_type != 8) {
return EXCEPTION_CONTINUE_EXECUTION;
}
}
}
return EXCEPTION_CONTINUE_SEARCH;
}

// register handler once, thread-safe bc of InitOnce
static INIT_ONCE mju_veh_init_once = INIT_ONCE_STATIC_INIT;

static BOOL CALLBACK mju_initVEH(INIT_ONCE* initOnce, void* param, void** ctx) {
AddVectoredExceptionHandler(1, mju_commitHandler);
return TRUE;
}

static void mju_ensureVEH(void) {
InitOnceExecuteOnce(&mju_veh_init_once, mju_initVEH, NULL, NULL);
}

#endif // _WIN32


static inline void* mju_alignedMalloc(size_t size, size_t align) {
#ifdef _WIN32
if (size >= MJU_LARGE_ALLOC_THRESHOLD) {
// install lazy-commit handler
mju_ensureVEH();
// MEM_RESERVE only: reserves virtual address space without commit charge
return VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_READWRITE);
}
return _aligned_malloc(size, align);
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
return aligned_alloc(align, size);
Expand All @@ -39,7 +90,13 @@ static inline void* mju_alignedMalloc(size_t size, size_t align) {

static inline void mju_alignedFree(void* ptr) {
#ifdef _WIN32
_aligned_free(ptr);
// determine which allocator owns this pointer
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(ptr, &mbi, sizeof(mbi)) != 0 && mbi.AllocationBase == ptr) {
VirtualFree(ptr, 0, MEM_RELEASE);
} else {
_aligned_free(ptr);
}
#else
free(ptr);
#endif
Expand Down
Loading