mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03: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
@ -12,6 +12,7 @@
|
||||
// standard windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// MAME headers
|
||||
#include "osdcore.h"
|
||||
@ -75,7 +76,21 @@ static memory_entry *free_list;
|
||||
static int current_id;
|
||||
|
||||
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
|
||||
//============================================================
|
||||
|
||||
INLINE void global_init_if_not_done(void)
|
||||
{
|
||||
if (!global_init_done)
|
||||
{
|
||||
global_init_done = TRUE;
|
||||
global_init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INLINE void memory_lock_acquire(void)
|
||||
{
|
||||
if (!memory_lock_initialized)
|
||||
{
|
||||
memory_lock_initialized = TRUE;
|
||||
InitializeCriticalSection(&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
|
||||
//============================================================
|
||||
|
||||
//============================================================
|
||||
// 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)
|
||||
{
|
||||
UINT8 *block_base;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 *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 != 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)
|
||||
{
|
||||
return realloc_file_line(memory, size, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// free - override for the free() function
|
||||
//============================================================
|
||||
|
||||
void CLIB_DECL free(void *memory)
|
||||
{
|
||||
memory_entry *entry;
|
||||
@ -352,7 +316,8 @@ void CLIB_DECL free(void *memory)
|
||||
if (memory == NULL)
|
||||
return;
|
||||
|
||||
if (use_malloc_tracking())
|
||||
// only proceed if enabled
|
||||
if (use_malloc_tracking)
|
||||
{
|
||||
// error if no entry found
|
||||
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 result;
|
||||
|
||||
if (use_malloc_tracking())
|
||||
// only proceed if enabled
|
||||
if (use_malloc_tracking)
|
||||
{
|
||||
memory_entry *entry = find_entry(memory);
|
||||
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)
|
||||
{
|
||||
memory_entry *entry;
|
||||
int total = 0;
|
||||
|
||||
if (use_malloc_tracking())
|
||||
// only valid if we are tracking
|
||||
if (use_malloc_tracking)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// 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 New Issue
Block a user