📄 xmem.c
字号:
/* linear address = segment * 16 + offset */
#define XMEM_LIN_ADDR(p) ((((UNS32)(p) & 0xffff0000L) >> 12) + ((UNS32)(p) & 0x0000ffffL))
#pragma message("XMEM_LIN_ADDR(p) for LARGE model")
#elif M_I86SM || __SMALL__ /**** small model: 2 byte pointer ****/
#define XMEM_LIN_ADDR(p) ((UNS32)(p) & 0x0000ffffL)
#pragma message("XMEM_LIN_ADDR(p) for SMALL model")
#else
#error unsupported memory model, only SMALL or LARGE model are implemented
#endif
#else /**** flat model, linear address space ****/
#define XMEM_LIN_ADDR(p) (PTRCAST)(p) /* pointer is already linear */
#pragma message("XMEM_LIN_ADDR(p) for flat model/linear address space")
#endif
/* Note: the following check does not always work because
sizeof() is only supported by some preprocessors.
Therefore it is disabled */
/*
#if sizeof(void *) > sizeof(UNS32)
#error unsupported pointer size
#endif
*/
/**** source code location of function calls ****/
#if XMEM_WHERE /* print source location */
#define MEM_LOCATE_TEXT(a,x,y,z,b) xmem_printf("%s '%s()' <%s,%lu>%s", (char *)(a), \
(char *)((x) ? (x) : FUNCTION_UNKNOWN), \
(char *)((y) ? (y) : FILENAME_UNKNOWN), \
(unsigned long)z, (char *)(b));
#define MEM_LOCATE(x,y,z) MEM_LOCATE_TEXT("",x,y,z,"")
#else
#define MEM_LOCATE_TEXT(a,x,y,z,b)
#define MEM_LOCATE(x,y,z)
#endif /* XMEM_WHERE */
/**** source location of last visit in any XMEM trace function ****/
#if XMEM_WHERE && XMEM_VISIT /* remember source location for last visit */
#define LAST_VISIT() xmem_printf(" [last XMEM visit at %s() <%s,%lu>]", \
(char *)((visit_callname) ? (visit_callname) : FUNCTION_UNKNOWN), \
(char *)((visit_fname) ? (visit_fname) : FILENAME_UNKNOWN), \
(unsigned long)visit_line);
#define THIS_VISIT(x,y,z) { visit_callname = ((x) ? (x) : FUNCTION_UNKNOWN); \
visit_fname = ((y) ? (y) : FILENAME_UNKNOWN); \
visit_line = (z); }
#else
#define LAST_VISIT()
#define THIS_VISIT(x,y,z)
#endif /* XMEM_WHERE && XMEM_VISIT */
/**** string length limit ****/
#define XMEM_STREOS_LIMIT 4000 /* warn, if EOS not within limit (change limit value if necessary) */
/**** GNU specific things ****/
#if __GNUC__
char *strrev(char *);
int strcmpi(const char *, const char *);
#endif
#if GNUTEST /* just to satisfy prototyping (GNU-C 2.2.2) */
int memicmp(const void *, const void *, unsigned int);
int stricmp(const char *, const char *);
#endif
#define OBJ_ARR_LEN_OFFS 4 /* object array length offset for new[] and delete[] */
/*****************************************************************************/
/*****************************************************************************/
/* local types */
/*****************************************************************************/
/*****************************************************************************/
#if XMEM_CALLSTACK
/* this part is Microsoft specific */
struct _s_callstack_entry /* one call stack frame */
{
SGN08 *funcname; /* function name */
SGN08 *filename; /* filename */
UNS32 lineno; /* line number */
DWORD64 offset; /* address offset */
};
typedef struct _s_callstack_entry S_CALLSTACK_ENTRY;
#define MAX_CALLSTACK 15 /* number of stack frames being handled */
struct _s_callstack /* wrapper structure for all stack frames */
{
S_CALLSTACK_ENTRY entry[MAX_CALLSTACK];
};
typedef struct _s_callstack S_CALLSTACK;
#endif /* endif XMEM_CALLSTACK */
struct _s_allocation
{
size_t size; /* size of memory block, including overhead */
UNS32 alloc_nr; /* allocation # */
UNS32 free_nr; /* free # */
SGN32 scope_level; /* scope # */
void *ptr; /* pointer to memory block */
void *freed; /* pointer to freed memory block */
SGN08 *funcname; /* name of alloc function */
#if XMEM_WHERE
const SGN08 *cname; /* name of calling function */
const SGN08 *fname; /* filename where initial allocation occured */
const SGN08 *realloc_cname; /* name of calling function where realloc occured */
const SGN08 *realloc_fname; /* filename where realloc occured */
const SGN08 *free_cname; /* name of calling function where final free occured */
const SGN08 *free_fname; /* filename where final free occured */
UNS32 line; /* line number where initial allocation occured */
UNS32 realloc_line; /* line number where realloc occured */
UNS32 free_line; /* line number where final free occured */
#endif
#if defined(_MSC_VER)
struct _timeb timebuf; /* allocation time */
#else
time_t ltime; /* allocation time */
#endif
#if XMEM_CALLSTACK
S_CALLSTACK cstk; /* call stack */
S_CALLSTACK realloc_cstk; /* call stack */
S_CALLSTACK free_cstk; /* call stack */
#endif
};
typedef struct _s_allocation S_ALLOCATION;
struct _s_slot
{
struct _s_slot *next; /* pointer to next slot in sub-linked list */
UNS16 entries; /* number of entries in this sub-linked list */
S_ALLOCATION *alloc; /* pointer to allocation trace block */
};
typedef struct _s_slot S_SLOT;
struct _s_scope
{
const SGN08 *scope_cname; /* scope function name */
const SGN08 *scope_fname; /* scope filename */
UNS32 scope_line; /* scope linen number */
};
typedef struct _s_scope S_SCOPE;
#if XMEM_WHERE
struct _s_functions
{
struct _s_functions *next; /* link to next element */
const SGN08 *callname; /* functionname */
UNS32 count; /* usage counter */
};
typedef struct _s_functions S_FUNCTIONS;
struct _s_files
{
struct _s_files *next; /* link to next element */
const SGN08 *filename; /* filename */
UNS32 count; /* usage counter */
struct _s_functions *root; /* link to funtions within this file */
};
typedef struct _s_files S_FILES;
static void xmem_add_callname(S_FILES *pfiles, const SGN08 *callname);
static void xmem_add_filename_callname(const SGN08 *filename, const SGN08 *callname);
#endif /* XMEM_WHERE */
/*****************************************************************************/
/*****************************************************************************/
/* local variables */
/*****************************************************************************/
/*****************************************************************************/
static S_SLOT **ptrhash = (S_SLOT **)NULL; /**** hash table root entry ****/
static BOOLEAN flag_ptrhash = FALSE; /* flag to indicate repeated hash table allocation */
static UNS16 memtrace = XMEM_TRACE; /* memory trace control variable */
static UNS16 memtrace_save = 0;
static UNS16 memtrace_realloc = FALSE; /* memory trace control variable */
static UNS16 memtrace_realloc_save = 0;
static UNS16 inside_realloc = FALSE; /* flag for realloc */
static size_t xmem_max_heapsize = (size_t)-1;/* maximum allowed heapsize */
#if XMEM_STRESS
static UNS16 xmem_stress_ratio = 0; /* stress ratio in [%] (0...100) */
#endif
struct _s_counters
{
size_t sum_progmem; /* overall # of bytes allocated */
size_t act_progmem; /* actual # of bytes allocated */
size_t total_progmem; /* maximum # of bytes allocated from program */
size_t total_memory; /* total # of bytes allocated */
UNS32 total_alloc; /* # of alloc calls, program + memcontrol */
UNS32 total_progalloc; /* # of alloc calls from program, done */
UNS32 total_alloc_call; /* # of alloc calls from program */
UNS32 total_realloc_call; /* # of alloc calls from program */
UNS32 total_expand_call; /* # of alloc calls from program */
UNS32 total_free; /* # of free calls, program + memcontrol */
UNS32 total_progfree; /* # of free calls from program, done */
UNS32 total_free_call; /* # of free calls from program */
UNS32 total_realloc_NULL; /* # of reallo calls with NULL */
UNS32 total_expand_NULL; /* # of _expand calls with NULL */
UNS32 malloc_call; /* # of calls */
UNS32 calloc_call; /* # of calls */
UNS32 realloc_call; /* # of calls */
UNS32 expand_call; /* # of calls */
UNS32 alloca_call; /* # of calls */
UNS32 free_call; /* # of calls */
UNS32 new_call; /* # of calls */
UNS32 new_array_call; /* # of calls */
UNS32 delete_call; /* # of calls */
UNS32 delete_array_call; /* # of calls */
UNS32 strdup_call; /* # of calls */
};
typedef struct _s_counters S_COUNTERS;
static S_COUNTERS counters; /* statistics */
#define SUB_LIMIT(x,y) (((x) > (y)) ? ((x) - (y)) : 0)
#if XMEM_WHERE && XMEM_VISIT
static const SGN08 *visit_callname = NULL;
static const SGN08 *visit_fname = NULL;
static UNS32 visit_line = 0;
#endif
static UNS16 trace_alloc_flag = FALSE;
static UNS32 trace_alloc_nr = 0;
static UNS16 trace_free_flag = FALSE;
static UNS32 trace_free_nr = 0;
#if XMEM_WHERE
static S_FILES *pfiles_root = NULL;
#endif
#define SCOPE_DEPTH 20 /* initial scope nesting depth */
static SGN32 scope_level = 0; /* actual scope level (= array index) */
static SGN32 scope_depth = 0; /* actual maximum scope depth */
static S_SCOPE *scope_stack = NULL; /* the scope stack array */
static const SGN08 *loc_cname = FUNCTION_UNKNOWN; /* call name */
static const SGN08 *loc_fname = FILENAME_UNKNOWN; /* function name */
static UNS32 loc_line = 0; /* line number */
#if XMEM_LOGFILE /* logfile for memory function call tracing */
static FILE *p_xmem_logfile = NULL;
static const char *xmem_logfilename = "xmem.log"; /* the logfile filename */
static UNS32 xmem_logcount = 0;
#if XMEM_HTMLLOGFILE
static FILE *p_xmem_htmllogfile = NULL;
static const char *xmem_htmllogfilename = "xmem_log.html"; /* the HTML filename */
#endif
#endif
#if XMEM_ERRLOGFILE /* logfile for error messages */
static FILE *p_xmem_errlogfile = NULL;
static const char *xmem_errlogfilename = "xmem_err.log"; /* the errorlogfile filename */
#endif
static BOOLEAN B_do_print = TRUE;
static BOOLEAN B_do_log = TRUE;
/**** operator delete stack ****/
#ifdef __cplusplus
#if XMEM_CPP_DELETE_STACK
#define XMEM_DELETE_STACK_SIZE 300
static S_SCOPE xmem_delete_stack[XMEM_DELETE_STACK_SIZE];
static SGN32 xmem_delete_stack_count = 0;
int xmem_delete_lock = 0;
#endif
#endif
/**** calculate the allocation limit for given type "size_t": 2^(sizeof(size_t) * 8) - 1 ****/
/* this works for all sizes of size_t and for all pointer sizes */
/* do it "by hand" to avoid including "math.h" */
static double get_alloc_limit(void)
{
unsigned int exponent = sizeof(size_t) * 8; /* (number of bytes) * ((number of bits) / byte) */
double pow2;
for (pow2 = 1.0; exponent > 0; --exponent)
{
pow2 *= 2.0;
}
return(pow2 - 1.0);
}
static double alloc_limit = 0.0; /* the "natural" allocation limit: */
/* maximum value that can be stored in a "size_t" value */
/**** for the statistical purposes ****/
#if XMEM_STATS /* array for statistical calculations (histogram) */
/* categories: 0, <=5, <=10, <=50, <=100, <=500, <=1000, <=5000, <=10000, */
/* <=50000, <=100000, <=500000, <=1000000, >1000000 */
#define STATSLOTS 14
struct _s_stats
{
UNS32 stats[STATSLOTS];
};
typedef struct _s_stats S_STATS;
static S_STATS stats = { { 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L } };
#endif
#if XMEM_STATS
static void xmem_statistics(size_t size);
#endif
/**** some SXT specific internal settings ****/
#if GNUCPP /* GNUCPP */
#ifdef XMEM_SXT
#undef XMEM_SXT
#endif
#define XMEM_SXT 1
#endif /* GNUCPP */
#if XMEM_SXT /* XMEM_SXT */
#ifdef __cplusplus
extern "C" {
#endif
extern unsigned long memory_allocated; /* currently allocated memory */
extern unsigned long memory_total_allocated; /* total allocated memory */
extern unsigned long memory_max_allocated; /* maximum allocated memory */
extern unsigned long memory_alloc_calls; /* number of memory allocation calls */
extern unsigned long memory_free_calls; /* number of memory free calls */
#ifdef __cplusplus
}
#endif
#endif /* XMEM_SXT */
/**** END OF some SXT specific internal settings ****/
/**** for XMEM_ALLOC_CALL (call redirection with detours) ****/
#if XMEM_ALLOC_CALL
static SGN32 xmem_call_internal = FALSE;
static BOOLEAN xmem_call_init = FALSE;
static BOOLEAN xmem_call_quiet = FALSE;
static void xmem_call_setup(void);
static void xmem_call_shutdown(void);
#define XMEM_CALL_INTERNAL_LOCK() ++xmem_call_internal /* set flag to avoid recursion */
#define XMEM_CALL_INTERNAL_UNLOCK() --xmem_call_internal; /* reset flag to avoid recursion */ \
if (xmem_call_internal < 0) \
{ xmem_printf("\nWARNING: internal call unlock underflow"); xmem_call_internal = 0; }
#else
#define XMEM_CALL_INTERNAL_LOCK()
#define XMEM_CALL_INTERNAL_UNLOCK()
#endif
/**** for XMEM_ALLOC_LIB (library call interception) ****/
#if XMEM_ALLOC_LIB
static BOOLEAN xmem_lib_init = FALSE; /* XMEM lib initialization status */
static BOOLEAN xmem_lib_quiet = TRUE; /* quiet mode, no call to output functions */
static void xmem_lib_setup(void);
#if _DEBUG /* Microsoft specific _xxx_dbg functions */
#define DBG_PARAMS_PROTO , int, const char *, int
#define DBG_PARAMS , _NORMAL_BLOCK, __FILE__, (int)__LINE__
#else /**/
#define DBG_PARAMS_PROTO
#define DBG_PARAMS
#endif /**/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -