//============================================================ // // winmisc.c - Win32 OSD core miscellaneous functions // //============================================================ // // Copyright Aaron Giles // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // * Redistributions in binary form must reproduce the // above copyright notice, this list of conditions and // the following disclaimer in the documentation and/or // other materials provided with the distribution. // * Neither the name 'MAME' nor the names of its // contributors may be used to endorse or promote // products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGE (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //============================================================ // standard windows headers #define WIN32_LEAN_AND_MEAN #include #include // MAME headers #include "osdcore.h" // MAMEOS headers #include "winutf8.h" #include "strconv.h" #include "strconv.h" //============================================================ // MACROS //============================================================ // presumed size of a page of memory #define PAGE_SIZE 4096 // align allocations to start or end of the page? #define GUARD_ALIGN_START 0 //============================================================ // GLOBAL VARIABLES //============================================================ void (*s_debugger_stack_crawler)() = NULL; //============================================================ // osd_malloc //============================================================ void *osd_malloc(size_t size) { #ifndef MALLOC_DEBUG return HeapAlloc(GetProcessHeap(), 0, size); #else // add in space for the size size += sizeof(size_t); // basic objects just come from the heap void *result = HeapAlloc(GetProcessHeap(), 0, size); // store the size and return and pointer to the data afterward *reinterpret_cast(result) = size; return reinterpret_cast(result) + sizeof(size_t); #endif } //============================================================ // osd_malloc_array //============================================================ void *osd_malloc_array(size_t size) { #ifndef MALLOC_DEBUG return HeapAlloc(GetProcessHeap(), 0, size); #else // add in space for the size size += sizeof(size_t); // round the size up to a page boundary size_t rounded_size = ((size + sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; // reserve that much memory, plus two guard pages void *page_base = VirtualAlloc(NULL, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS); if (page_base == NULL) return NULL; // now allow access to everything but the first and last pages page_base = VirtualAlloc(reinterpret_cast(page_base) + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE); if (page_base == NULL) return NULL; // work backwards from the page base to get to the block base void *result = GUARD_ALIGN_START ? page_base : (reinterpret_cast(page_base) + rounded_size - size); // store the size at the start with a flag indicating it has a guard page *reinterpret_cast(result) = size | 0x80000000; return reinterpret_cast(result) + sizeof(size_t); #endif } //============================================================ // osd_free //============================================================ void osd_free(void *ptr) { #ifndef MALLOC_DEBUG HeapFree(GetProcessHeap(), 0, ptr); #else size_t size = reinterpret_cast(ptr)[-1]; // if no guard page, just free the pointer if ((size & 0x80000000) == 0) HeapFree(GetProcessHeap(), 0, reinterpret_cast(ptr) - sizeof(size_t)); // large items need more care else { ULONG_PTR page_base = (reinterpret_cast(ptr) - sizeof(size_t)) & ~(PAGE_SIZE - 1); VirtualFree(reinterpret_cast(page_base - PAGE_SIZE), 0, MEM_RELEASE); } #endif } //============================================================ // osd_alloc_executable //============================================================ void *osd_alloc_executable(size_t size) { return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); } //============================================================ // osd_free_executable //============================================================ void osd_free_executable(void *ptr, size_t size) { VirtualFree(ptr, 0, MEM_RELEASE); } //============================================================ // osd_break_into_debugger //============================================================ void osd_break_into_debugger(const char *message) { if (IsDebuggerPresent()) { win_output_debug_string_utf8(message); DebugBreak(); } else if (s_debugger_stack_crawler != NULL) (*s_debugger_stack_crawler)(); }