📄 xmem.c
字号:
static void *(*xmem_malloc_ptr)(size_t DBG_PARAMS_PROTO) = NULL;
static void *(*xmem_calloc_ptr)(size_t, size_t DBG_PARAMS_PROTO) = NULL;
static void *(*xmem_realloc_ptr)(void *, size_t DBG_PARAMS_PROTO) = NULL;
static void *(*xmem_expand_ptr)(void *, size_t DBG_PARAMS_PROTO) = NULL;
static void (*xmem_free_ptr)(void * DBG_PARAMS_PROTO) = NULL;
static char *(*xmem_strdup_ptr)(const char *) = NULL;
#define XMEM_MALLOC__(s) xmem_malloc_ptr(s DBG_PARAMS)
#define XMEM_CALLOC__(c,s) xmem_calloc_ptr(c,s DBG_PARAMS)
#define XMEM_REALLOC__(p,s) xmem_realloc_ptr(p,s DBG_PARAMS)
#define XMEM_EXPAND__(p,s) xmem_expand_ptr(p,s DBG_PARAMS)
#define XMEM_FREE__(p) xmem_free_ptr(p DBG_PARAMS)
#define XMEM_STRDUP__ xmem_strdup_ptr
#else /* XMEM_ALLOC_LIB */
#define XMEM_MALLOC__ malloc
#define XMEM_CALLOC__ calloc
#define XMEM_REALLOC__ realloc
#define XMEM_EXPAND__ _expand
#define XMEM_FREE__ free
#define XMEM_STRDUP__ strdup
#endif /* XMEM_ALLOC_LIB */
/*****************************************************************************/
/*****************************************************************************/
/* multi threading */
/*****************************************************************************/
/*****************************************************************************/
#if XMEM_THREAD
static HANDLE xmem_hSem = NULL;
#define XMEM_THREAD_ENTER_CRITICAL_SECTION() { if (xmem_hSem == NULL) \
{ xmem_hSem = CreateMutex(NULL, TRUE, (PTR2STR)"XMEM"); } \
else \
{ WaitForSingleObject(xmem_hSem, INFINITE); } \
}
#define XMEM_THREAD_LEAVE_CRITICAL_SECTION() ReleaseMutex(xmem_hSem)
#else
#define XMEM_THREAD_ENTER_CRITICAL_SECTION()
#define XMEM_THREAD_LEAVE_CRITICAL_SECTION()
#endif
/*****************************************************************************/
/*****************************************************************************/
/* call stack tracing */
/*****************************************************************************/
/*****************************************************************************/
#if XMEM_CALLSTACK /* XMEM_CALLSTACK */
#define CALLS_LIMIT_INITIAL 40 /* initial number of calls between hash optimization */
#define CALLS_LIMIT 100000 /* upper limit of calls for hash optimization */
struct _s_names /* used to store names */
{
struct _s_names *next; /* pointer to next element */
SGN08 *name; /* pointer to name */
};
typedef struct _s_names S_NAMES;
static S_NAMES *xmem_name_hashtable[XMEM_HASHSIZE]; /* hashtable for names */
static UNS16 xmem_string_hashfunc(SGN08 *);
static SGN08 *xmem_add_name(SGN08 *);
static S_NAMES *xmem_append_name(SGN08 *, S_NAMES *);
static S_NAMES *xmem_search_name(SGN08 *, S_NAMES *);
static void xmem_deinit_names(void);
struct _s_callstack_hash_entry /* one call stack frame hash entry */
{
S_CALLSTACK_ENTRY entry; /* stack entry element */
#if XMEM_CALLSTACK_HASH
UNS32 hits; /* number of hits */
#endif
struct _s_callstack_hash_entry *next; /* next stack entry */
};
typedef struct _s_callstack_hash_entry S_CALLSTACK_HASH_ENTRY;
static S_CALLSTACK g_cstk; /* local static object used for call stack handling */
/**** derived XMEM_StackWalker class ****/
class XMEM_StackWalker : public StackWalker
{
public:
int m_entry_index; /* index for call stack frame */
#if XMEM_CALLSTACK_HASH
UNS32 m_calls;
UNS32 m_calls_limit;
#endif
static S_CALLSTACK *m_pcstk; /* pointer to call stack structure */
static S_CALLSTACK_HASH_ENTRY *m_phashroot; /* pointer to call stack hash */
static UNS32 m_hashcnt;
static SGN32 m_stack_depth_warning;
/**** constructor ****/
XMEM_StackWalker() : StackWalker()
{
#if XMEM_CALLSTACK_HASH
m_calls = 0;
m_calls_limit = CALLS_LIMIT_INITIAL;
#endif
};
/**** constructor ****/
XMEM_StackWalker(DWORD dwProcessId, HANDLE hProcess) : StackWalker(dwProcessId, hProcess) {};
/**** destructor ****/
virtual ~XMEM_StackWalker()
{
S_CALLSTACK_HASH_ENTRY *pentry, *pentry_next;
for (pentry = m_phashroot; pentry != NULL; pentry = pentry_next)
{ /* free address entry element */
pentry_next = pentry->next;
XMEM_CALL_INTERNAL_LOCK();
XMEM_FREE__(pentry);
XMEM_CALL_INTERNAL_UNLOCK();
}
m_phashroot = NULL;
m_hashcnt = 0;
};
/**** process and add one callstack entry ****/
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
if ((eType != lastEntry) && (entry.offset != 0))
{
if (m_entry_index < MAX_CALLSTACK)
{ /* one valid callstack entry within logging index limit */
if (m_pentry == NULL) /* is address already known? */
{
/* get the function name */
if (entry.undFullName[0] != 0)
m_pcstk->entry[m_entry_index].funcname = xmem_add_name(entry.undFullName);
else if (entry.undName[0] != 0)
m_pcstk->entry[m_entry_index].funcname = xmem_add_name(entry.undName);
else
m_pcstk->entry[m_entry_index].funcname = xmem_add_name("(function-name not available)");
/* get the filename */
if (entry.lineFileName[0] == 0)
{
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "0x%p (%s): %s", (LPVOID)entry.offset,
(entry.moduleName[0] == 0) ? "(module-name not available)"
: entry.moduleName,
"(filename not available)"
);
m_pcstk->entry[m_entry_index].filename = xmem_add_name(buffer);
}
else
{
m_pcstk->entry[m_entry_index].filename = xmem_add_name(entry.lineFileName);
}
m_pcstk->entry[m_entry_index].lineno = (UNS32)entry.lineNumber; /* get the line number */
m_pcstk->entry[m_entry_index].offset = entry.offset; /* address offset */
add_entry(entry.offset, &m_pcstk->entry[m_entry_index]); /* remember address entry element */
}
else
{ /* address entry is knwon, simply copy it */
m_pcstk->entry[m_entry_index] = ((S_CALLSTACK_HASH_ENTRY *)m_pentry)->entry;
}
}
else
{ /* maximum call stack depth exceeded */
if (m_entry_index > m_stack_depth_warning)
{
xmem_printf("\nREMARK: XMEM internal maximum trace call stack depth exceeded (%ld > %ld)",
(SGN32)m_entry_index,
(SGN32)MAX_CALLSTACK
);
m_stack_depth_warning = m_entry_index;
}
}
}
++m_entry_index; /* increment logging index */
};
virtual void OnDbgHelpErr(LPCSTR /* szFuncName */, DWORD /* gle */, DWORD64 /* addr */) { };
virtual void OnOutput(LPCSTR /* szText */) { };
virtual void OnOutput(LPCWSTR /* szText */) { };
/**** initialize callstack displaying ****/
void init_ShowCallstack(void)
{
m_entry_index = 0; /* init the stack frame index */
if (m_pcstk)
{
memset(m_pcstk, 0, sizeof(S_CALLSTACK)); /* initialize the call stack frame structure */
}
};
/**** search callstack entry ****/
void *search_entry(DWORD64 offset)
{ /* search if address is already known */
S_CALLSTACK_HASH_ENTRY *pentry;
for (pentry = m_phashroot; pentry != NULL; pentry = pentry->next)
{
if (pentry->entry.offset == offset)
{ /* entry found, leave for loop */
#if XMEM_CALLSTACK_HASH
++pentry->hits;
#endif
goto LBL_END;
}
}
LBL_END:
#if XMEM_CALLSTACK_HASH
if (++m_calls > m_calls_limit)
{ /* limit reached, reorganize hash list to optimize access */
S_CALLSTACK_HASH_ENTRY *pentry1, *pentry2, *pentry_tmp;
S_CALLSTACK_ENTRY tmp_entry;
UNS32 tmp_hits;
UNS08 is_reorganized = FALSE;
for (pentry1 = m_phashroot; pentry1 != NULL; pentry1 = pentry1->next)
{ /* sort hash list entries in descending hit order */
pentry_tmp = NULL;
for (pentry2 = pentry1->next; pentry2 != NULL; pentry2 = pentry2->next)
{ /* find largest hit value in remaining list */
if ( ( (pentry_tmp == NULL)
&& (pentry2->hits > pentry1->hits)
)
|| ( (pentry_tmp != NULL)
&& (pentry2->hits > pentry_tmp->hits)
)
)
{
pentry_tmp = pentry2; /* remember entry */
}
}
if ( (pentry_tmp != NULL)
&& (pentry_tmp != pentry1)
)
{ /* new largest hit value found, exchange entries in place */
tmp_entry = pentry_tmp->entry;
tmp_hits = pentry_tmp->hits;
pentry_tmp->entry = pentry1->entry;
pentry_tmp->hits = pentry1->hits;
pentry1->entry = tmp_entry;
pentry1->hits = tmp_hits;
if (pentry1->entry.offset == offset)
{
pentry = pentry1;
}
is_reorganized = TRUE; /* remember that exchange took place */
}
}
m_calls = 0; /* reset value */
if (is_reorganized == FALSE)
{ /* no reorganization, increase limit */
if (m_calls_limit < CALLS_LIMIT)
{ /* since calls limit is not reached */
m_calls_limit *= 2; /* multiply limit with factor 2 */
}
}
}
#endif
return(pentry);
}
/**** add callstack entry ****/
S_CALLSTACK_HASH_ENTRY *add_entry(DWORD64 offset, S_CALLSTACK_ENTRY *entry)
{ /* add address entry element */
S_CALLSTACK_HASH_ENTRY *pentry, *plastentry = NULL;
if (m_phashroot == NULL)
{ /* no list element present, make first entry */
XMEM_CALL_INTERNAL_LOCK();
pentry = (S_CALLSTACK_HASH_ENTRY *)XMEM_CALLOC__(1,
sizeof(S_CALLSTACK_HASH_ENTRY)
);
XMEM_CALL_INTERNAL_UNLOCK();
m_phashroot = pentry;
}
else
{ /* search linked list for entry */
for (pentry = m_phashroot; pentry != NULL; pentry = pentry->next)
{
if (pentry->entry.offset == offset)
{
return(pentry); /* identical entry already in list */
}
plastentry = pentry;
}
XMEM_CALL_INTERNAL_LOCK();
pentry = (S_CALLSTACK_HASH_ENTRY *)XMEM_CALLOC__(1,
sizeof(S_CALLSTACK_HASH_ENTRY)
);
XMEM_CALL_INTERNAL_UNLOCK();
plastentry->next = pentry;
}
pentry->entry = *entry; /* copy complete address element */
pentry->entry.offset = offset; /* remember address */
++m_hashcnt; /* increment hash entry counter */
return(pentry);
}
};
S_CALLSTACK *XMEM_StackWalker::m_pcstk = &g_cstk; /* set static class pointer to call stack frame structure object */
S_CALLSTACK_HASH_ENTRY *XMEM_StackWalker::m_phashroot = NULL; /* initialize hash pointer */
UNS32 XMEM_StackWalker::m_hashcnt = 0;
SGN32 XMEM_StackWalker::m_stack_depth_warning = MAX_CALLSTACK;
static XMEM_StackWalker sw; /* create one callstack instance */
static BOOLEAN cstck_flag = FALSE;
#define GET_XMEM_CALLSTACK() { if (cstck_flag == FALSE) { cstck_flag = TRUE; sw.init_ShowCallstack(); sw.ShowCallstack(); cstck_flag = FALSE; } }
static void xmem_show_callstack(S_CALLSTACK *p_cstk);
#define XMEM_SHOW_CALLSTACK(x) { if (cstck_flag == FALSE) { cstck_flag = TRUE; xmem_show_callstack(x); cstck_flag = FALSE; } }
#else /* XMEM_CALLSTACK */
#define GET_XMEM_CALLSTACK()
#define XMEM_SHOW_CALLSTACK(x)
#endif /* XMEM_CALLSTACK */
/*****************************************************************************/
/*****************************************************************************/
/* XMEM settings, displayed during compilation and written to error logfile */
/*****************************************************************************/
/*****************************************************************************/
void xmem_settings(FILE *fptr)
{
#if XMEM_SETTINGS
fprintf(fptr, "\n******** XMEM settings ********\n");
#if XMEM
#pragma message("XMEM enabled")
fprintf(fptr, "XMEM enabled\n");
#else
#pragma message("XMEM disabled")
fprintf(fptr, "XMEM disabled\n");
#endif
#if XMEM_CPP
#pragma message("XMEM_CPP enabled")
fprintf(fptr, "XMEM_CPP enabled\n");
#else
#pragma message("XMEM_CPP disabled")
fprintf(fptr, "XMEM_CPP disabled\n");
#endif
#if XMEM_CRITICAL_OPERATOR
#pragma message("XMEM_CRITICAL_OPERATOR enabled")
fprintf(fptr, "XMEM_CRITICAL_OPERATOR enabled\n");
#else
#pragma message("XMEM_CRITICAL_OPERATOR disabled")
fprintf(fptr, "XMEM_CRITICAL_OPERATOR disabled\n");
#endif
#if XMEM_NEWARRAY
#pragma message("XMEM_NEWARRAY enabled")
fprintf(fptr, "XMEM_NEWARRAY enabled\n");
#else
#pragma message("XMEM_NEWARRAY disabled")
fprintf(fptr, "XMEM_NEWARRAY disabled\n");
#endif
#if XMEM_DELETEARRAY
#pragma message("XMEM_DELETEARRAY enabled")
fprintf(fptr, "XMEM_DELETEARRAY enabled\n");
#else
#pragma message("XMEM_DELETEARRAY disabled")
fprintf(fptr, "XMEM_DELETEARRAY disabled\n");
#endif
#if XMEM_CPP_DELETE_STACK
#pragma message("XMEM_CPP_DELETE_STACK enabled")
fprintf(fptr, "XMEM_CPP_DELETE_STACK enabled\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -