mirror of
https://github.com/mamedev/mame.git
synced 2024-11-16 07:48:32 +01:00
(Windows only)
Added code to debug 64-bit builds to allocate all address space below 4GB to help find 64-bit errors. Added environment variable OSDDEBUGMALLOC which, if set, explicitly overrides the debug malloc debug settings. Added environment variable OSDDEBUG4GB which, if set, explicitly overrides the new 64-bit address space allocations. (Sadly this is necessary due to my nvidia D3D drivers being 64-bit unclean....)
This commit is contained in:
parent
1ee549675e
commit
a3b57f5fd5
1 changed files with 241 additions and 111 deletions
|
@ -12,6 +12,7 @@
|
||||||
// standard windows headers
|
// standard windows headers
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
// MAME headers
|
// MAME headers
|
||||||
#include "osdcore.h"
|
#include "osdcore.h"
|
||||||
|
@ -75,7 +76,21 @@ static memory_entry *free_list;
|
||||||
static int current_id;
|
static int current_id;
|
||||||
|
|
||||||
static CRITICAL_SECTION memory_lock;
|
static CRITICAL_SECTION memory_lock;
|
||||||
static UINT8 memory_lock_initialized = FALSE;
|
|
||||||
|
static UINT8 global_init_done = FALSE;
|
||||||
|
static UINT8 use_malloc_tracking = FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// PROTOTYPES
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
static memory_entry *allocate_entry(void);
|
||||||
|
static memory_entry *find_entry(void *pointer);
|
||||||
|
static void free_entry(memory_entry *entry);
|
||||||
|
|
||||||
|
static void global_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,13 +98,18 @@ static UINT8 memory_lock_initialized = FALSE;
|
||||||
// INLINES
|
// INLINES
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
|
INLINE void global_init_if_not_done(void)
|
||||||
|
{
|
||||||
|
if (!global_init_done)
|
||||||
|
{
|
||||||
|
global_init_done = TRUE;
|
||||||
|
global_init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
INLINE void memory_lock_acquire(void)
|
INLINE void memory_lock_acquire(void)
|
||||||
{
|
{
|
||||||
if (!memory_lock_initialized)
|
|
||||||
{
|
|
||||||
memory_lock_initialized = TRUE;
|
|
||||||
InitializeCriticalSection(&memory_lock);
|
|
||||||
}
|
|
||||||
EnterCriticalSection(&memory_lock);
|
EnterCriticalSection(&memory_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,116 +120,26 @@ INLINE void memory_lock_release(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
INLINE memory_entry *allocate_entry(void)
|
|
||||||
{
|
|
||||||
memory_entry *entry;
|
|
||||||
|
|
||||||
memory_lock_acquire();
|
|
||||||
|
|
||||||
// if we're out of entries, allocate some more
|
|
||||||
if (free_list == NULL)
|
|
||||||
{
|
|
||||||
int entries_per_page = PAGE_SIZE / sizeof(memory_entry);
|
|
||||||
|
|
||||||
// allocate a new pages' worth of entry
|
|
||||||
entry = (memory_entry *)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
|
|
||||||
if (entry == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Out of memory for malloc tracking!\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add all the entries to the list
|
|
||||||
while (entries_per_page--)
|
|
||||||
{
|
|
||||||
entry->next = free_list;
|
|
||||||
free_list = entry;
|
|
||||||
entry++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// grab a free list entry
|
|
||||||
entry = free_list;
|
|
||||||
free_list = free_list->next;
|
|
||||||
|
|
||||||
// add ourselves to the alloc list
|
|
||||||
entry->next = alloc_list;
|
|
||||||
if (entry->next)
|
|
||||||
entry->next->prev = entry;
|
|
||||||
entry->prev = NULL;
|
|
||||||
alloc_list = entry;
|
|
||||||
|
|
||||||
memory_lock_release();
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
INLINE memory_entry *find_entry(void *pointer)
|
|
||||||
{
|
|
||||||
memory_entry *entry;
|
|
||||||
|
|
||||||
// scan the list looking for a matching base
|
|
||||||
if (pointer)
|
|
||||||
{
|
|
||||||
memory_lock_acquire();
|
|
||||||
|
|
||||||
for (entry = alloc_list; entry; entry = entry->next)
|
|
||||||
if (entry->base == pointer)
|
|
||||||
break;
|
|
||||||
|
|
||||||
memory_lock_release();
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
INLINE void free_entry(memory_entry *entry)
|
|
||||||
{
|
|
||||||
memory_lock_acquire();
|
|
||||||
|
|
||||||
// remove ourselves from the alloc list
|
|
||||||
if (entry->prev)
|
|
||||||
entry->prev->next = entry->next;
|
|
||||||
else
|
|
||||||
alloc_list = entry->next;
|
|
||||||
if (entry->next)
|
|
||||||
entry->next->prev = entry->prev;
|
|
||||||
|
|
||||||
// add ourself to the free list
|
|
||||||
entry->next = free_list;
|
|
||||||
free_list = entry;
|
|
||||||
|
|
||||||
memory_lock_release();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
INLINE int use_malloc_tracking(void)
|
|
||||||
{
|
|
||||||
#ifdef MESS
|
|
||||||
extern BOOL win_is_gui_application(void);
|
|
||||||
return !win_is_gui_application();
|
|
||||||
#elif defined(WINUI)
|
|
||||||
return FALSE;
|
|
||||||
#else
|
|
||||||
return TRUE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// IMPLEMENTATION
|
// IMPLEMENTATION
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// malloc_file_line - debugging version of malloc which
|
||||||
|
// accepts filename and line number
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *malloc_file_line(size_t size, const char *file, int line)
|
void *malloc_file_line(size_t size, const char *file, int line)
|
||||||
{
|
{
|
||||||
UINT8 *block_base;
|
UINT8 *block_base;
|
||||||
int id = current_id++;
|
int id = current_id++;
|
||||||
|
|
||||||
|
// perform global intialization if not already done
|
||||||
|
global_init_if_not_done();
|
||||||
|
|
||||||
if (use_malloc_tracking())
|
// only proceed if enabled
|
||||||
|
if (use_malloc_tracking)
|
||||||
{
|
{
|
||||||
UINT8 *page_base;
|
UINT8 *page_base;
|
||||||
size_t rounded_size;
|
size_t rounded_size;
|
||||||
|
@ -259,12 +189,21 @@ void *malloc_file_line(size_t size, const char *file, int line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// malloc - override for the malloc() function
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *CLIB_DECL malloc(size_t size)
|
void *CLIB_DECL malloc(size_t size)
|
||||||
{
|
{
|
||||||
return malloc_file_line(size, NULL, 0);
|
return malloc_file_line(size, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// calloc_file_line - debugging version of calloc which
|
||||||
|
// accepts filename and line number
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *calloc_file_line(size_t size, size_t count, const char *file, int line)
|
void *calloc_file_line(size_t size, size_t count, const char *file, int line)
|
||||||
{
|
{
|
||||||
// first allocate the memory
|
// first allocate the memory
|
||||||
|
@ -278,24 +217,41 @@ void *calloc_file_line(size_t size, size_t count, const char *file, int line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// calloc - override for the calloc() function
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *CLIB_DECL calloc(size_t size, size_t count)
|
void *CLIB_DECL calloc(size_t size, size_t count)
|
||||||
{
|
{
|
||||||
return calloc_file_line(size, count, NULL, 0);
|
return calloc_file_line(size, count, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// this function is called by beginthreadex
|
//============================================================
|
||||||
|
// _calloc_crt - override for the _calloc_crt() function,
|
||||||
|
// which is called by beginthreadex
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *CLIB_DECL _calloc_crt(size_t size, size_t count)
|
void *CLIB_DECL _calloc_crt(size_t size, size_t count)
|
||||||
{
|
{
|
||||||
return calloc_file_line(size, count, NULL, 0);
|
return calloc_file_line(size, count, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// realloc_file_line - debugging version of realloc which
|
||||||
|
// accepts filename and line number
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *realloc_file_line(void *memory, size_t size, const char *file, int line)
|
void *realloc_file_line(void *memory, size_t size, const char *file, int line)
|
||||||
{
|
{
|
||||||
void *newmemory = NULL;
|
void *newmemory = NULL;
|
||||||
|
|
||||||
if (use_malloc_tracking())
|
// perform global intialization if not already done
|
||||||
|
global_init_if_not_done();
|
||||||
|
|
||||||
|
// only proceed if enabled
|
||||||
|
if (use_malloc_tracking)
|
||||||
{
|
{
|
||||||
// if size is non-zero, we need to reallocate memory
|
// if size is non-zero, we need to reallocate memory
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
|
@ -338,12 +294,20 @@ void *realloc_file_line(void *memory, size_t size, const char *file, int line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// realloc - override for the realloc() function
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void *CLIB_DECL realloc(void *memory, size_t size)
|
void *CLIB_DECL realloc(void *memory, size_t size)
|
||||||
{
|
{
|
||||||
return realloc_file_line(memory, size, NULL, 0);
|
return realloc_file_line(memory, size, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// free - override for the free() function
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void CLIB_DECL free(void *memory)
|
void CLIB_DECL free(void *memory)
|
||||||
{
|
{
|
||||||
memory_entry *entry;
|
memory_entry *entry;
|
||||||
|
@ -352,7 +316,8 @@ void CLIB_DECL free(void *memory)
|
||||||
if (memory == NULL)
|
if (memory == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (use_malloc_tracking())
|
// only proceed if enabled
|
||||||
|
if (use_malloc_tracking)
|
||||||
{
|
{
|
||||||
// error if no entry found
|
// error if no entry found
|
||||||
entry = find_entry(memory);
|
entry = find_entry(memory);
|
||||||
|
@ -381,11 +346,17 @@ void CLIB_DECL free(void *memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// _msize - internal MSVC routine that returns the size of
|
||||||
|
// a memory block
|
||||||
|
//============================================================
|
||||||
|
|
||||||
size_t CLIB_DECL _msize(void *memory)
|
size_t CLIB_DECL _msize(void *memory)
|
||||||
{
|
{
|
||||||
size_t result;
|
size_t result;
|
||||||
|
|
||||||
if (use_malloc_tracking())
|
// only proceed if enabled
|
||||||
|
if (use_malloc_tracking)
|
||||||
{
|
{
|
||||||
memory_entry *entry = find_entry(memory);
|
memory_entry *entry = find_entry(memory);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
|
@ -407,12 +378,18 @@ size_t CLIB_DECL _msize(void *memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// check_unfreed_mem - called from the exit path of any
|
||||||
|
// code that wants to check for unfreed memory
|
||||||
|
//============================================================
|
||||||
|
|
||||||
void check_unfreed_mem(void)
|
void check_unfreed_mem(void)
|
||||||
{
|
{
|
||||||
memory_entry *entry;
|
memory_entry *entry;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
if (use_malloc_tracking())
|
// only valid if we are tracking
|
||||||
|
if (use_malloc_tracking)
|
||||||
{
|
{
|
||||||
memory_lock_acquire();
|
memory_lock_acquire();
|
||||||
|
|
||||||
|
@ -432,3 +409,156 @@ void check_unfreed_mem(void)
|
||||||
fprintf(stderr, "a total of %d bytes were not free()'d\n", total);
|
fprintf(stderr, "a total of %d bytes were not free()'d\n", total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// allocate_entry - allocate a new entry and link it into
|
||||||
|
// the list of allocated memory
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
static memory_entry *allocate_entry(void)
|
||||||
|
{
|
||||||
|
memory_entry *entry;
|
||||||
|
|
||||||
|
// always take the lock when allocating
|
||||||
|
memory_lock_acquire();
|
||||||
|
|
||||||
|
// if we're out of entries, allocate some more
|
||||||
|
if (free_list == NULL)
|
||||||
|
{
|
||||||
|
int entries_per_page = PAGE_SIZE / sizeof(memory_entry);
|
||||||
|
|
||||||
|
// allocate a new pages' worth of entry
|
||||||
|
entry = (memory_entry *)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (entry == NULL)
|
||||||
|
{
|
||||||
|
memory_lock_release();
|
||||||
|
fprintf(stderr, "Out of memory for malloc tracking!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all the entries to the list
|
||||||
|
while (entries_per_page--)
|
||||||
|
{
|
||||||
|
entry->next = free_list;
|
||||||
|
free_list = entry;
|
||||||
|
entry++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab a free list entry
|
||||||
|
entry = free_list;
|
||||||
|
free_list = free_list->next;
|
||||||
|
|
||||||
|
// add ourselves to the alloc list
|
||||||
|
entry->next = alloc_list;
|
||||||
|
if (entry->next)
|
||||||
|
entry->next->prev = entry;
|
||||||
|
entry->prev = NULL;
|
||||||
|
alloc_list = entry;
|
||||||
|
|
||||||
|
// release the lock when finished
|
||||||
|
memory_lock_release();
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// find_entry - find a memory_object entry in the list that
|
||||||
|
// contains the given pointer
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
static memory_entry *find_entry(void *pointer)
|
||||||
|
{
|
||||||
|
memory_entry *entry;
|
||||||
|
|
||||||
|
// scan the list looking for a matching base
|
||||||
|
if (pointer)
|
||||||
|
{
|
||||||
|
memory_lock_acquire();
|
||||||
|
|
||||||
|
for (entry = alloc_list; entry; entry = entry->next)
|
||||||
|
if (entry->base == pointer)
|
||||||
|
break;
|
||||||
|
|
||||||
|
memory_lock_release();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// free_entry - free a memory_entry object
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
static void free_entry(memory_entry *entry)
|
||||||
|
{
|
||||||
|
memory_lock_acquire();
|
||||||
|
|
||||||
|
// remove ourselves from the alloc list
|
||||||
|
if (entry->prev)
|
||||||
|
entry->prev->next = entry->next;
|
||||||
|
else
|
||||||
|
alloc_list = entry->next;
|
||||||
|
if (entry->next)
|
||||||
|
entry->next->prev = entry->prev;
|
||||||
|
|
||||||
|
// add ourself to the free list
|
||||||
|
entry->next = free_list;
|
||||||
|
free_list = entry;
|
||||||
|
|
||||||
|
memory_lock_release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================
|
||||||
|
// global_init - global initialization of memory variables
|
||||||
|
//============================================================
|
||||||
|
|
||||||
|
static void global_init(void)
|
||||||
|
{
|
||||||
|
TCHAR *envstring;
|
||||||
|
|
||||||
|
// create the memory lock
|
||||||
|
InitializeCriticalSection(&memory_lock);
|
||||||
|
|
||||||
|
// determine if we enabled by default
|
||||||
|
#ifdef MESS
|
||||||
|
extern BOOL win_is_gui_application(void);
|
||||||
|
use_malloc_tracking = !win_is_gui_application();
|
||||||
|
#elif defined(WINUI)
|
||||||
|
use_malloc_tracking = FALSE;
|
||||||
|
#else
|
||||||
|
use_malloc_tracking = TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// now allow overrides by the environment
|
||||||
|
envstring = _tgetenv(_T("OSDDEBUGMALLOC"));
|
||||||
|
if (envstring != NULL)
|
||||||
|
use_malloc_tracking = (_ttoi(envstring) != 0);
|
||||||
|
|
||||||
|
#ifdef PTR64
|
||||||
|
// 64-bit builds also can allocate everything under 4GB, unless disabled
|
||||||
|
envstring = _tgetenv(_T("OSDDEBUG4GB"));
|
||||||
|
if (envstring == NULL || _ttoi(envstring) != 0)
|
||||||
|
{
|
||||||
|
INT8 allocshift;
|
||||||
|
|
||||||
|
// loop from 256MB down to 4k (page size)
|
||||||
|
for (allocshift = 8 + 20; allocshift >= 12; allocshift--)
|
||||||
|
{
|
||||||
|
// keep allocating address space at that size until we get something >4gb
|
||||||
|
while ((UINT64)VirtualAlloc(NULL, (UINT64)1 << allocshift, MEM_RESERVE, PAGE_NOACCESS) < ((UINT64)1 << 32)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop from 64k down
|
||||||
|
for (allocshift = 6 + 10; allocshift >= 1; allocshift--)
|
||||||
|
{
|
||||||
|
// keep allocating memory until we get something >4gb
|
||||||
|
while ((UINT64)GlobalAlloc(GMEM_FIXED, (UINT64)1 << allocshift) < ((UINT64)1 << 32)) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue