1838 lines
59 KiB
C
1838 lines
59 KiB
C
/************************************************************************/
|
|
/* SISCO SOFTWARE MODULE HEADER *****************************************/
|
|
/************************************************************************/
|
|
/* (c) Copyright Systems Integration Specialists Company, Inc., */
|
|
/* 1986-2008 All Rights Reserved */
|
|
/* */
|
|
/* MODULE NAME : mem_chks.c */
|
|
/* PRODUCT(S) : MMSEASE */
|
|
/* */
|
|
/* MODULE DESCRIPTION : */
|
|
/* This module contains enhanced memory allocation functions */
|
|
/* for performing various integrity checks */
|
|
/* */
|
|
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
|
|
/* */
|
|
/* MODIFICATION LOG : */
|
|
/* Date Who Rev Comments */
|
|
/* -------- --- ------ ------------------------------------------- */
|
|
/* 03/04/08 EJV 56 _nd_chk_* corr: del ++/-- chk_curr_mem_count;*/
|
|
/* (was not protected in multithreaded apps). */
|
|
/* m_mem_debug: init to SD_TRUE for lib products*/
|
|
/* 10/04/07 MDE 55 Tweaked LOGCFG_VALUE_GROUP/LOGCFGX_VALUE_MAP */
|
|
/* 01/15/07 EJV 54 Chg S_LOCK_RESOURCES to S_LOCK_UTIL_RESOURCES*/
|
|
/* 10/25/06 MDE 53 Removed msjexhnd.h include */
|
|
/* 08/23/06 DSF 52 Call to ExpInit () no longer needed */
|
|
/* 08/09/06 JRB 51 Log error if m_mem_debug changed after startup*/
|
|
/* 07/14/06 DSF 50 Ported to VS2005 compiler */
|
|
/* 03/01/06 EJV 49 Moved mem_chk.h outside define. */
|
|
/* 02/28/06 RLH 48 avoid duplicate definition of #define */
|
|
/* 01/30/06 GLB 47 Integrated porting changes for VMS */
|
|
/* 10/13/05 EJV 46 dyn_mem_ptr_status2: combined 2 slogs. */
|
|
/* 05/11/05 MDE 45 Minor logging */
|
|
/* 05/23/05 EJV 44 Add memLogMaskMapCtrl & memDebugMapCtrl */
|
|
/* for parsing logcfg.xml */
|
|
/* 05/11/05 MDE 43 Now do list check for chk_calloc too */
|
|
/* 03/10/04 EJV 42 Use '%lu' and typecast to (ST_ULONG) for */
|
|
/* ST_UINT32 logging. */
|
|
/* 02/06/04 EJV 42 Added dyn_mem_ptr_status2. */
|
|
/* Use '%u' when logging memory statistics. */
|
|
/* 06/06/03 JRB 41 Use S_LOCK_RESOURCES (new util mutex). */
|
|
/* 04/08/03 DSF 40 1) No need to lock common resources in nd_ */
|
|
/* functions or when checking if we've been */
|
|
/* initialized */
|
|
/* 2) Use Microsoft CRT Debug calls when */
|
|
/* MEMCHK_WIN32_CRT_DEBUG is defined and */
|
|
/* m_mem_crt_debug is set */
|
|
/* 03/06/02 JRB 39 Add S_UNLOCK.. before ret in chk_alloc_ptr. */
|
|
/* 02/11/02 DSF 38 Add a call to ExpInit () */
|
|
/* 10/18/01 JRB 37 Eliminate warning. Fix *_memerr_fun calls. */
|
|
/* 10/10/01 JRB 36 Del unused valid_string function. */
|
|
/* 09/19/01 JRB 35 Add NULL ptr check in dyn_mem_ptr_status. */
|
|
/* 08/29/01 EJV 34 mem_report: prevented stack overflow. */
|
|
/* 08/20/01 JRB 33 If !DEBUG_SISCO, chk_* macros call nd_chk_*. */
|
|
/* If DEBUG_SISCO, chk_* macros call x_chk_*. */
|
|
/* nd_* functions use CHK_DYN_MEM_NODE_NDEBUG */
|
|
/* Globals calling_file/line deleted (see args).*/
|
|
/* Del (x_)chk_free_wipe functions. */
|
|
/* 08/20/01 JRB 32 Del m_pad_string_len (use m_num_pad_bytes) */
|
|
/* 08/20/01 JRB 31 Default m_find_node_enable=FALSE (faster). */
|
|
/* Ignore m_track_prev_free (not effective). */
|
|
/* 08/16/01 JRB 30 Delete SAVE_CALLING_ADDRESS code for DOS. */
|
|
/* 04/02/01 JRB 29 ALWAYS call init_mem_chk automatically (not */
|
|
/* depending on DEBUG_SISCO or m_mem_debug). */
|
|
/* Fix previous chg to save m_mem_debug value. */
|
|
/* 03/27/01 GLB 28 Added MEMCHK_WIN32_CRT_DEBUG */
|
|
/* 03/03/01 GLB 27 save m_mem_debug in m_mem_debug_saved */
|
|
/* 02/23/01 DSF 26 m_mem_debug should not be initialized to TRUE*/
|
|
/* 01/30/01 DSF 25 Added WIN32 Debug CRT memory checks */
|
|
/* 04/28/00 JRB 24 Lint cleanup. */
|
|
/* 04/19/00 JRB 23 Del SD_CONST from def_realloc_err arg. */
|
|
/* Fix "uninitialized" warnings in chk_realloc. */
|
|
/* 10/13/99 RKR 22 Cast file to a ST_CHAR *, fixed a prototype */
|
|
/* 09/13/99 MDE 21 Added SD_CONST modifiers */
|
|
/* 09/07/99 MDE 20 Minor optimization for calloc (1, x) */
|
|
/* 04/14/99 MDE 19 Cleaned up system dependency stuff a bit */
|
|
/* 04/14/99 MDE 18 Fixed 'chk_strdup' file/line */
|
|
/* 03/05/98 MDE 17 Added 'chk_strdup' */
|
|
/* 02/23/99 RKR 16 fixed the redefinition of new_mem_node */
|
|
/* 02/15/99 DSF 15 fixed a bug in the new chk_calloc() routine -*/
|
|
/* don't fill allocated buffer */
|
|
/* 02/09/99 DSF 14 chk_calloc () now makes direct calls to */
|
|
/* RTL calloc () - faster */
|
|
/* 02/02/99 JRB 13 Add "()" in free calls in chk_free: */
|
|
/* helps some "free" macros work. */
|
|
/* Don't init chk_debug_en in declaration: */
|
|
/* some compilers put it in ROM (unchangable). */
|
|
/* Don't use obsolete MEMCHK_ERR_PRINT. */
|
|
/* 12/08/98 MDE 12 Added 'ST_BOOLEAN m_auto_hw_log' */
|
|
/* 10/09/98 MDE 11 Changed 'MEMLOG_CHERR' usage per new macros */
|
|
/* 10/08/98 MDE 10 Migrated to updated SLOG interface */
|
|
/* 09/21/98 MDE 09 Minor lint cleanup */
|
|
/* 06/15/98 MDE 08 Changes to allow compile under C++ */
|
|
/* 01/30/98 EJV 07 Added typecating (ST_VOID **) in list funcs. */
|
|
/* 10/14/97 DSF 06 m_bad_ptr_val is now a pointer */
|
|
/* 10/13/97 DSF 05 Initialize chk_debug_en = MEM_LOG_ERR */
|
|
/* 09/16/97 DSF 04 chk_debug_en is UINT */
|
|
/* 06/19/97 RKR 03 Changed return code from MEM_PTR_CHK_ERROR2 */
|
|
/* 05/27/97 DSF 02 Minor bug fix */
|
|
/* 05/20/97 RKR 01 Changed default of m_mem_debug to SD_TRUE */
|
|
/* 04/02/97 DTL 7.00 MMSEASE 7.0 release. See MODL70.DOC for */
|
|
/* history. */
|
|
/************************************************************************/
|
|
|
|
#include "glbtypes.h"
|
|
#include "sysincs.h"
|
|
#include "glbsem.h"
|
|
#include "mem_chk.h"
|
|
|
|
#define MEM_CHK /* used in mem_chk.h */
|
|
#include "memlog.h"
|
|
#include "gen_list.h"
|
|
#include <ctype.h>
|
|
|
|
/* WIN32 CRT Debug used for all but MMS-EASE Lite users */
|
|
/* MMS-EASE Lite users can define in project if desired ... */
|
|
#if defined (_WIN32) && defined (_DEBUG) && !defined(MMS_LITE)
|
|
#ifndef MEMCHK_WIN32_CRT_DEBUG
|
|
#define MEMCHK_WIN32_CRT_DEBUG
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
#include <crtdbg.h>
|
|
int mem_report (int reportType, char *userMessage, int *retVal);
|
|
ST_BOOLEAN m_mem_crt_debug;
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/************************************************************************/
|
|
/* These should be defined on the compiler command line */
|
|
/* #define DEBUG */
|
|
/* #define NO_REALLOC_SMALLER */
|
|
|
|
#if (((defined(MSDOS) || defined(__MSDOS__)) && !defined(_WIN32)) && !defined(_WINDOWS))
|
|
#define MSOFT_HEAP_CHECK
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* For debug version, use a static pointer to avoid duplication of */
|
|
/* __FILE__ strings. */
|
|
|
|
#ifdef DEBUG_SISCO
|
|
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* These functions (with leading '_') are EXACTLY the same as the */
|
|
/* "nd_chk_*" functions, but they are static so they can only be */
|
|
/* called by the "x_chk_*" functions within this module, and */
|
|
/* only if DEBUG_SISCO is defined. */
|
|
/* This prevents the user from mixing debug and non-debug calling code. */
|
|
/* If this module is compiled with DEBUG_SISCO defined, then ALL user */
|
|
/* code must be compiled with DEBUG_SISCO defined, and the user code */
|
|
/* will call "x_chk_*". */
|
|
/* If this module is compiled with DEBUG_SISCO !defined, then ALL user*/
|
|
/* code must be compiled with DEBUG_SISCO !defined, and the user code */
|
|
/* will call "nd_chk_*". */
|
|
/************************************************************************/
|
|
#ifdef DEBUG_SISCO
|
|
static ST_VOID *_nd_chk_malloc (ST_UINT size);
|
|
static ST_VOID *_nd_chk_calloc (ST_UINT num, ST_UINT size);
|
|
static ST_VOID *_nd_chk_realloc (ST_VOID *ptr, ST_UINT size);
|
|
static ST_VOID _nd_chk_free (ST_VOID *del_mem_ptr);
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/************************************************************************/
|
|
/* DEBUG related defines & variables (leave declared for both versions) */
|
|
|
|
ST_BOOLEAN m_mem_debug = SD_TRUE;
|
|
#ifdef DEBUG_SISCO
|
|
static ST_BOOLEAN m_mem_debug_saved;
|
|
#endif
|
|
ST_VOID *m_bad_ptr_val;
|
|
|
|
/* Use 4 bytes (default) at the end of each buffer for overwrite detect */
|
|
/* Default value used will be 0xDEADBEEF */
|
|
ST_CHAR *m_pad_string;
|
|
ST_INT m_num_pad_bytes;
|
|
|
|
/* Use this to fill malloc'ed and freed memory with garbage */
|
|
ST_UCHAR m_fill_byte;
|
|
ST_BOOLEAN m_fill_en;
|
|
|
|
/* This variable used to enable MSOFT heap check calls on every alloc */
|
|
/* and free call. */
|
|
ST_BOOLEAN m_heap_check_enable;
|
|
|
|
/* This variable used to enable list validation and overwrite checking */
|
|
/* on every alloc and free call. */
|
|
ST_BOOLEAN m_check_list_enable;
|
|
|
|
/* Set this variable SD_FALSE to speed up the debug version. When SD_TRUE, it */
|
|
/* enables searching the memory list for the element before accessing */
|
|
/* the memory during chk_realloc and chk_free calls */
|
|
ST_BOOLEAN m_find_node_enable;
|
|
|
|
/* This variable will cause chk_realloc to not realloc when the new */
|
|
/* size is smaller than the old size */
|
|
ST_BOOLEAN m_no_realloc_smaller;
|
|
|
|
/* Dump memory table whenever high water mark is advanced */
|
|
ST_BOOLEAN m_auto_hw_log;
|
|
|
|
ST_BOOLEAN m_track_prev_free; /* NOT USED. Only for backward compat. */
|
|
|
|
/* Bit masked logging control variable */
|
|
ST_UINT chk_debug_en;
|
|
|
|
#ifdef DEBUG_SISCO
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_err_logstr = "MEM_LOG_ERR";
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_calloc_logstr = "MEM_LOG_CALLOC";
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_malloc_logstr = "MEM_LOG_MALLOC";
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_realloc_logstr = "MEM_LOG_REALLOC";
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_free_logstr = "MEM_LOG_FREE";
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_nerr_logstr = "MEM_LOG_NERR";
|
|
SD_CONST ST_CHAR *SD_CONST _mem_log_dump_logstr = "MEM_LOG_DUMP";
|
|
LOGCFGX_VALUE_MAP memLogMaskMaps[] =
|
|
{
|
|
{"MEM_LOG_ERR", MEM_LOG_ERR, &chk_debug_en, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Error"},
|
|
{"MEM_LOG_CALLOC", MEM_LOG_CALLOC, &chk_debug_en, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Calloc"},
|
|
{"MEM_LOG_MALLOC", MEM_LOG_MALLOC, &chk_debug_en, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Malloc"},
|
|
{"MEM_LOG_REALLOC", MEM_LOG_REALLOC,&chk_debug_en, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Realloc"},
|
|
{"MEM_LOG_FREE", MEM_LOG_FREE, &chk_debug_en, _LOGCFG_DATATYPE_UINT_MASK, NULL, "Free"}
|
|
};
|
|
|
|
LOGCFG_VALUE_GROUP memLogMaskMapCtrl =
|
|
{
|
|
{NULL,NULL},
|
|
"MemLogMasks", /* Parent Tag */
|
|
sizeof(memLogMaskMaps)/sizeof(LOGCFGX_VALUE_MAP),
|
|
memLogMaskMaps
|
|
};
|
|
|
|
LOGCFGX_VALUE_MAP memDebugMaps[] =
|
|
{
|
|
/* Memory debugging */
|
|
{"MemFillEnable", 0, &m_fill_en, _LOGCFG_DATATYPE_BOOLEAN},
|
|
{"MemHeapCheck", 0, &m_heap_check_enable, _LOGCFG_DATATYPE_BOOLEAN},
|
|
{"MemCheckList", 0, &m_check_list_enable, _LOGCFG_DATATYPE_BOOLEAN},
|
|
{"MemFindNode", 0, &m_find_node_enable, _LOGCFG_DATATYPE_BOOLEAN},
|
|
{"MemNoReallocSmaller", 0, &m_no_realloc_smaller, _LOGCFG_DATATYPE_BOOLEAN},
|
|
|
|
/* Old names */
|
|
{"CheckListEnable", 0, &m_check_list_enable, _LOGCFG_DATATYPE_BOOLEAN},
|
|
{"FindNodeEnable", 0, &m_find_node_enable, _LOGCFG_DATATYPE_BOOLEAN},
|
|
{"NoReallocSmaller", 0, &m_no_realloc_smaller, _LOGCFG_DATATYPE_BOOLEAN}
|
|
};
|
|
|
|
LOGCFG_VALUE_GROUP memDebugMapCtrl =
|
|
{
|
|
{NULL,NULL},
|
|
"MemAllocDbgCtrl", /* Parent Tag */
|
|
sizeof(memDebugMaps)/sizeof(LOGCFGX_VALUE_MAP),
|
|
memDebugMaps
|
|
};
|
|
#endif /* DEBUG_SISCO */
|
|
|
|
/* Declarations for functions and array of structures used to keep track*/
|
|
/* of allocated memory. */
|
|
ST_UINT32 chk_curr_mem_count;
|
|
ST_UINT32 chk_max_dyn_mem_ptrs;
|
|
ST_UINT32 chk_max_mem_allocated;
|
|
ST_UINT32 chk_curr_mem_size;
|
|
|
|
/* This function pointer can be set to select a function to be called */
|
|
/* in case of memory error. */
|
|
ST_VOID (*mem_chk_err)(ST_VOID);
|
|
|
|
/************************************************************************/
|
|
/* Internal variables */
|
|
|
|
/* Memory block header, used for DEBUG to track all allocated memory */
|
|
|
|
#if defined(DEBUG_SISCO)
|
|
typedef struct chk_dyn_mem_node
|
|
{
|
|
DBL_LNK chk_mem_node_link;
|
|
ST_INT chk_alloc_mem_size;
|
|
ST_VOID *chk_alloc_mem_ptr;
|
|
ST_CHAR *file; /* File && line that allocated the memory */
|
|
ST_INT line;
|
|
ST_UINT16 overwrite_prev_detected; /* flag to indicate that */
|
|
/* overwrite previously detected */
|
|
SD_END_STRUCT
|
|
} CHK_DYN_MEM_NODE;
|
|
|
|
static CHK_DYN_MEM_NODE *head_dyn_mem_list;
|
|
|
|
#endif /* DEBUG_SISCO */
|
|
|
|
/* nd_* functions use CHK_DYN_MEM_NODE_NDEBUG. This saves overhead if */
|
|
/* !DEBUG_SISCO or if !m_mem_debug. */
|
|
typedef struct chk_dyn_mem_node_ndebug
|
|
{
|
|
ST_INT chk_alloc_mem_size;
|
|
SD_END_STRUCT
|
|
} CHK_DYN_MEM_NODE_NDEBUG;
|
|
|
|
/* The 'mem_chk' tools must be initialized before being used, esp. */
|
|
/* in DEBUG mode, or we may write or flush a NULL stream */
|
|
static ST_INT mem_chk_initialized;
|
|
|
|
/************************************************************************/
|
|
/* DEBUG internal variables and functions */
|
|
#ifdef DEBUG_SISCO
|
|
|
|
/* padding variables */
|
|
static ST_UINT mem_overhead;
|
|
|
|
static ST_RET check_overwrite (CHK_DYN_MEM_NODE *ptr);
|
|
static ST_VOID set_overwrite_value (CHK_DYN_MEM_NODE *ptr);
|
|
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* Internal functions */
|
|
|
|
static ST_VOID *def_malloc_err (ST_UINT size);
|
|
static ST_VOID *def_calloc_err (ST_UINT num, ST_UINT size);
|
|
static ST_VOID *def_realloc_err (ST_VOID *old, ST_UINT size);
|
|
static ST_VOID mem_fat_err (ST_VOID);
|
|
|
|
/************************************************************************/
|
|
/************************************************************************/
|
|
/* def_xxx_err */
|
|
/* default fatal error service functions - just return */
|
|
/************************************************************************/
|
|
|
|
static ST_VOID *def_malloc_err (ST_UINT size)
|
|
{
|
|
mem_fat_err ();
|
|
return (NULL);
|
|
}
|
|
|
|
static ST_VOID *def_calloc_err (ST_UINT num, ST_UINT size)
|
|
{
|
|
mem_fat_err ();
|
|
return (NULL);
|
|
}
|
|
|
|
static ST_VOID *def_realloc_err (ST_VOID *old, ST_UINT size)
|
|
{
|
|
mem_fat_err ();
|
|
return (NULL);
|
|
}
|
|
|
|
static ST_VOID mem_fat_err ()
|
|
{
|
|
#ifdef DEBUG_SISCO
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
MEMLOG_ERR0 ("Fatal Memory Allocation Error");
|
|
MEMLOG_CERR1 ("Current number of allocated buffers : %lu",
|
|
(ST_ULONG) chk_curr_mem_count);
|
|
MEMLOG_CERR1 ("Current amount of memory allocated : %lu",
|
|
(ST_ULONG) chk_curr_mem_size);
|
|
MEMLOG_CERR1 ("Maximum number of pointers allocated : %lu",
|
|
(ST_ULONG) chk_max_dyn_mem_ptrs);
|
|
MEMLOG_CERR1 ("Maximum amount of memory allocated : %lu",
|
|
(ST_ULONG) chk_max_mem_allocated);
|
|
MEMLOG_PAUSEERR ("");
|
|
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
|
|
dyn_mem_ptr_status ();
|
|
}
|
|
#endif /* no debug, do nothing. Can't printf because may be windowing. */
|
|
|
|
exit (255); /* the default action includes exit! */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* fatal error service function pointers, used for unrecoverable errors */
|
|
|
|
ST_VOID *(*m_memerr_fun)(ST_UINT size);
|
|
ST_VOID *(*c_memerr_fun)(ST_UINT num, ST_UINT size);
|
|
ST_VOID *(*r_memerr_fun)(ST_VOID *ptr, ST_UINT size);
|
|
|
|
/************************************************************************/
|
|
/* init_mem_chk */
|
|
/************************************************************************/
|
|
|
|
ST_VOID init_mem_chk ()
|
|
{
|
|
|
|
if (mem_chk_initialized)
|
|
{ /* do not allow reinitialize */
|
|
return;
|
|
}
|
|
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
if (m_mem_crt_debug)
|
|
m_mem_debug = SD_TRUE;
|
|
#endif
|
|
|
|
#ifdef DEBUG_SISCO
|
|
|
|
/* Save the current value of "m_mem_debug" to control debugging. */
|
|
/* If it is changed later, it has no impact. */
|
|
/* This prevents crashes caused by changing allocation mode in the */
|
|
/* middle of a program. */
|
|
|
|
m_mem_debug_saved = m_mem_debug;
|
|
|
|
chk_debug_en |= MEM_LOG_ERR;
|
|
|
|
if (m_bad_ptr_val == NULL)
|
|
m_bad_ptr_val = (ST_VOID *) -1;
|
|
if (m_pad_string == NULL)
|
|
m_pad_string = "\336\255\276\357"; /* 0xDEADBEEF */
|
|
if (m_num_pad_bytes == 0)
|
|
m_num_pad_bytes = 4;
|
|
if (m_fill_byte == 0)
|
|
m_fill_byte = (ST_UCHAR) 0xCC;
|
|
|
|
/* Calculate the debug memory overhead */
|
|
mem_overhead = sizeof (CHK_DYN_MEM_NODE) + m_num_pad_bytes;
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
/* hook a debug report function */
|
|
|
|
_CrtSetReportHook (mem_report);
|
|
|
|
{
|
|
int tmpFlag = _CrtSetDbgFlag (_CRTDBG_REPORT_FLAG);
|
|
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
|
|
|
|
if (m_heap_check_enable)
|
|
tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF;
|
|
|
|
/* Set the new state for the flag */
|
|
_CrtSetDbgFlag (tmpFlag);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
if (!m_memerr_fun)
|
|
m_memerr_fun = def_malloc_err;
|
|
if (!c_memerr_fun)
|
|
c_memerr_fun = def_calloc_err;
|
|
if (!r_memerr_fun)
|
|
r_memerr_fun = def_realloc_err;
|
|
mem_chk_initialized = SD_TRUE;
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
/************************************************************************/
|
|
/* mem_report */
|
|
/* Called by CRT Library to report a memory condition. */
|
|
/************************************************************************/
|
|
|
|
int mem_report (int reportType, char *userMessage, int *retVal)
|
|
{
|
|
static int fileCreated = SD_FALSE;
|
|
static HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD bytesWritten;
|
|
|
|
*retVal = 0;
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* if file already open that means that we are called again */
|
|
/* from the fprintf() below, */
|
|
/* exit to prevent stack overflow in fprintf when _HEAPBADNODE err */
|
|
return FALSE;
|
|
}
|
|
|
|
hFile = CreateFile("MemReport.log", GENERIC_WRITE,
|
|
FILE_SHARE_WRITE, NULL, fileCreated ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
fileCreated = SD_TRUE;
|
|
|
|
SetFilePointer (hFile, 0, NULL, FILE_END);
|
|
WriteFile(hFile, userMessage, strlen (userMessage), &bytesWritten, NULL);
|
|
|
|
CloseHandle (hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/************************************************************************/
|
|
/* x_chk_malloc */
|
|
/* get memory via malloc, check for error condition */
|
|
/* if error, invoke the fatal error function via pointer */
|
|
/************************************************************************/
|
|
|
|
#if defined(DEBUG_SISCO)
|
|
ST_VOID *x_chk_malloc (ST_UINT size,
|
|
SD_CONST ST_CHAR *SD_CONST calling_file,
|
|
SD_CONST ST_INT calling_line)
|
|
{
|
|
CHK_DYN_MEM_NODE *new_mem_node;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
if (m_mem_debug_saved != m_mem_debug)
|
|
{
|
|
MEMLOG_ERR1 ("ERROR: m_mem_debug flag changed to '%d' after first allocation. Not allowed so ignored.",
|
|
m_mem_debug);
|
|
m_mem_debug = m_mem_debug_saved; /* change it back so err logged only once*/
|
|
}
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
|
|
/* Do linked list && overwrite checks, if enabled */
|
|
if (m_check_list_enable)
|
|
check_mem_list ();
|
|
|
|
/* Perform heap validation, if enabled and the system supports it */
|
|
#if defined(DEBUG_SISCO) && defined (MSOFT_HEAP_CHECK)
|
|
if (m_heap_check_enable)
|
|
msoft_heap_check (0); /* do not print the heap! */
|
|
#endif
|
|
|
|
/* It is not OK to malloc a buffer of size 0 - check for this */
|
|
if (!size)
|
|
{
|
|
MEMLOG_ERR0 ("Attempting to malloc with size == 0");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
size++;
|
|
}
|
|
|
|
/* Allocate the buffer using the standard 'malloc' call */
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
if (m_mem_crt_debug)
|
|
new_mem_node = (CHK_DYN_MEM_NODE *) _malloc_dbg (size + mem_overhead, _NORMAL_BLOCK,
|
|
calling_file, calling_line);
|
|
else
|
|
new_mem_node = (CHK_DYN_MEM_NODE *) malloc (size + mem_overhead);
|
|
#else
|
|
new_mem_node = (CHK_DYN_MEM_NODE *) malloc (size + mem_overhead);
|
|
#endif
|
|
|
|
if (new_mem_node == NULL)
|
|
{ /* see if we can call a function to get some memory back*/
|
|
if (!(new_mem_node = (CHK_DYN_MEM_NODE *)
|
|
(*m_memerr_fun)(size + mem_overhead)))
|
|
{
|
|
MEMLOG_ERR0 ("WARNING : Returning NULL Pointer");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return (NULL); /* if we can't get any back we return a NULL */
|
|
}
|
|
}
|
|
|
|
/* Set up the memory control block header */
|
|
new_mem_node -> chk_alloc_mem_size = size;
|
|
new_mem_node -> chk_alloc_mem_ptr = (ST_VOID *)(new_mem_node+1);
|
|
|
|
/* Fill memory with garbage */
|
|
if (m_fill_en)
|
|
memset (new_mem_node -> chk_alloc_mem_ptr, m_fill_byte, size);
|
|
|
|
/* Save file and line numbers */
|
|
new_mem_node->file = (ST_CHAR *)calling_file;
|
|
new_mem_node->line = calling_line;
|
|
|
|
/* Set the overwrite detect value at the end of the buffer */
|
|
set_overwrite_value (new_mem_node);
|
|
|
|
/* Now add this element to the allocation control list */
|
|
list_add_first ((ST_VOID **)&head_dyn_mem_list, new_mem_node);
|
|
|
|
/* Update memory allocation statistics parameters */
|
|
chk_curr_mem_count++;
|
|
chk_curr_mem_size += size;
|
|
if (chk_curr_mem_count > chk_max_dyn_mem_ptrs)
|
|
chk_max_dyn_mem_ptrs = chk_curr_mem_count;
|
|
if (chk_curr_mem_size > chk_max_mem_allocated)
|
|
{
|
|
chk_max_mem_allocated = chk_curr_mem_size;
|
|
if (m_auto_hw_log)
|
|
dyn_mem_ptr_status ();
|
|
}
|
|
/* log allocation info, if enabled */
|
|
MEMLOG_MALLOC2 ("chk_malloc : size = %05u, ptr = %08lx"
|
|
,size, (ST_VOID *)(new_mem_node+1));
|
|
if (calling_line != -1)
|
|
{
|
|
MEMLOG_CMALLOC2 ("File : %s, Line %d",calling_file, calling_line);
|
|
}
|
|
|
|
/* return the user pointer */
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return ((ST_VOID *)(new_mem_node+1));
|
|
}
|
|
else /* !m_mem_debug_saved */
|
|
return (_nd_chk_malloc (size));
|
|
}
|
|
#endif /* DEBUG_SISCO */
|
|
|
|
/************************************************************************/
|
|
/* nd_chk_malloc */
|
|
/* This function is called if (!DEBUG_SISCO) OR (!m_mem_debug_saved). */
|
|
/************************************************************************/
|
|
#ifdef DEBUG_SISCO /* Use "static" for DEBUG, so user can't call. */
|
|
static ST_VOID *_nd_chk_malloc (ST_UINT size)
|
|
#else
|
|
ST_VOID *nd_chk_malloc (ST_UINT size)
|
|
#endif
|
|
{
|
|
CHK_DYN_MEM_NODE_NDEBUG *new_mem_node;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
new_mem_node =
|
|
(CHK_DYN_MEM_NODE_NDEBUG *) malloc (size + sizeof(CHK_DYN_MEM_NODE_NDEBUG));
|
|
if (new_mem_node == NULL)
|
|
{ /* malloc failed. Try err_fun to get mem*/
|
|
new_mem_node = (CHK_DYN_MEM_NODE_NDEBUG *)
|
|
(*m_memerr_fun)(size + sizeof(CHK_DYN_MEM_NODE_NDEBUG));
|
|
if (!new_mem_node)
|
|
{
|
|
return (NULL); /* can't get any back, so return NULL */
|
|
}
|
|
}
|
|
new_mem_node -> chk_alloc_mem_size = size;
|
|
return ((ST_VOID *)(new_mem_node+1));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* x_chk_calloc */
|
|
/* get memory via calloc, check for error condition */
|
|
/* if error, invoke the fatal error function via pointer */
|
|
/************************************************************************/
|
|
|
|
#if defined(DEBUG_SISCO)
|
|
ST_VOID *x_chk_calloc (ST_UINT num,
|
|
ST_UINT size,
|
|
SD_CONST ST_CHAR *SD_CONST calling_file,
|
|
SD_CONST ST_INT calling_line)
|
|
{
|
|
CHK_DYN_MEM_NODE *new_mem_node;
|
|
ST_INT buf_size;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
|
|
/* Do linked list && overwrite checks, if enabled */
|
|
if (m_check_list_enable)
|
|
check_mem_list ();
|
|
|
|
/* It is not OK to calloc a buffer of size 0 - check for this */
|
|
if (!size)
|
|
{
|
|
MEMLOG_ERR0 ("Attempting to calloc with size == 0");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
size++;
|
|
}
|
|
if (!num)
|
|
{
|
|
MEMLOG_ERR0 ("Attempting to calloc with num == 0");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
num++;
|
|
}
|
|
|
|
/* Calculate the size required ... Save a multiply? */
|
|
if (num == 1)
|
|
buf_size = size;
|
|
else if (size == 1)
|
|
buf_size = num;
|
|
else
|
|
buf_size = num * size;
|
|
|
|
/* get the buffer */
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
if (m_mem_crt_debug)
|
|
new_mem_node = (CHK_DYN_MEM_NODE *) _calloc_dbg (1, buf_size + mem_overhead, _NORMAL_BLOCK,
|
|
calling_file, calling_line);
|
|
else
|
|
new_mem_node = (CHK_DYN_MEM_NODE *) calloc (1, buf_size + mem_overhead);
|
|
#else
|
|
new_mem_node = (CHK_DYN_MEM_NODE *) calloc (1, buf_size + mem_overhead);
|
|
#endif
|
|
|
|
/* verify NULL not returned */
|
|
if (!new_mem_node)
|
|
{
|
|
MEMLOG_ERR0 ("WARNING : Returning NULL Pointer");
|
|
MEMLOG_CERR5 ("Parameters: num:%d size: %d file:%s line:%d %s",
|
|
num, size, calling_file, calling_line, "");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return (NULL);
|
|
}
|
|
|
|
/* Set up the memory control block header */
|
|
new_mem_node -> chk_alloc_mem_size = buf_size;
|
|
new_mem_node -> chk_alloc_mem_ptr = (ST_VOID *)(new_mem_node+1);
|
|
|
|
/* Save file and line numbers */
|
|
new_mem_node->file = (ST_CHAR *)calling_file;
|
|
new_mem_node->line = calling_line;
|
|
|
|
/* Set the overwrite detect value at the end of the buffer */
|
|
set_overwrite_value (new_mem_node);
|
|
|
|
/* Now add this element to the allocation control list */
|
|
list_add_first ((ST_VOID **)&head_dyn_mem_list, new_mem_node);
|
|
|
|
/* Update memory allocation statistics parameters */
|
|
chk_curr_mem_count++;
|
|
chk_curr_mem_size += buf_size;
|
|
if (chk_curr_mem_count > chk_max_dyn_mem_ptrs)
|
|
chk_max_dyn_mem_ptrs = chk_curr_mem_count;
|
|
if (chk_curr_mem_size > chk_max_mem_allocated)
|
|
{
|
|
chk_max_mem_allocated = chk_curr_mem_size;
|
|
if (m_auto_hw_log)
|
|
dyn_mem_ptr_status ();
|
|
}
|
|
|
|
/* log allocation info, if enabled */
|
|
MEMLOG_CALLOC3 ("chk_calloc : num = %05u, size = %05u Ptr = %08lx",num,size,new_mem_node+1);
|
|
if (calling_line != -1)
|
|
{
|
|
MEMLOG_CCALLOC2 ("File : %s, Line %d",calling_file, calling_line);
|
|
}
|
|
|
|
/* return the user pointer */
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return ((ST_VOID *)(new_mem_node+1));
|
|
}
|
|
else /* !m_mem_debug_saved */
|
|
return (_nd_chk_calloc (num, size));
|
|
}
|
|
#endif /* DEBUG_SISCO */
|
|
|
|
/************************************************************************/
|
|
/* nd_chk_calloc */
|
|
/* This function is called if (!DEBUG_SISCO) OR (!m_mem_debug_saved). */
|
|
/************************************************************************/
|
|
#ifdef DEBUG_SISCO /* Use "static" for DEBUG, so user can't call. */
|
|
static ST_VOID *_nd_chk_calloc (ST_UINT num, ST_UINT size)
|
|
#else
|
|
ST_VOID *nd_chk_calloc (ST_UINT num, ST_UINT size)
|
|
#endif
|
|
{
|
|
CHK_DYN_MEM_NODE_NDEBUG *new_mem_node;
|
|
ST_INT buf_size;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
buf_size = num * size; /* chk_malloc adds overhead */
|
|
new_mem_node =
|
|
(CHK_DYN_MEM_NODE_NDEBUG *) calloc (1, buf_size + sizeof(CHK_DYN_MEM_NODE_NDEBUG));
|
|
if (new_mem_node == NULL)
|
|
{ /* calloc failed. Try err_fun to get mem*/
|
|
new_mem_node = (CHK_DYN_MEM_NODE_NDEBUG *)
|
|
(*c_memerr_fun)(1, buf_size + sizeof(CHK_DYN_MEM_NODE_NDEBUG));
|
|
if (!new_mem_node)
|
|
{
|
|
return (NULL); /* can't get any back, so return NULL */
|
|
}
|
|
}
|
|
new_mem_node -> chk_alloc_mem_size = buf_size;
|
|
return ((ST_VOID *)(new_mem_node+1));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* x_chk_realloc */
|
|
/* get memory via calloc, check for error condition */
|
|
/* if error, invoke the fatal error function via pointer */
|
|
/************************************************************************/
|
|
|
|
#if defined(DEBUG_SISCO)
|
|
ST_VOID *x_chk_realloc (ST_VOID *ptr,
|
|
ST_UINT size,
|
|
SD_CONST ST_CHAR *SD_CONST calling_file,
|
|
SD_CONST ST_INT calling_line)
|
|
{
|
|
CHK_DYN_MEM_NODE *old_mem_node, *new_mem_node;
|
|
ST_VOID *old_mem_ptr;
|
|
ST_UINT old_mem_size;
|
|
ST_BOOLEAN no_realloc;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
/* Do linked list && overwrite checks, if enabled */
|
|
if (m_check_list_enable)
|
|
check_mem_list ();
|
|
|
|
/* Perform heap validation, if enabled and the system supports it */
|
|
#if defined(DEBUG_SISCO) && defined (MSOFT_HEAP_CHECK)
|
|
if (m_heap_check_enable)
|
|
msoft_heap_check (0); /* do not print the heap! */
|
|
#endif
|
|
|
|
/* It is not OK to pass in a NULL pointer, check for this */
|
|
if (!ptr)
|
|
{
|
|
MEMLOG_ERR2 ("File : %s, Line %d",
|
|
calling_file, calling_line);
|
|
MEMLOG_CERR0 ("Attempting to realloc NULL pointer");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return (NULL);
|
|
}
|
|
|
|
/* It is not OK to re-alloc a buffer of size 0 - check for this */
|
|
if (!size)
|
|
{
|
|
MEMLOG_ERR0 ( "Attempting to realloc with size = 0");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
size++;
|
|
}
|
|
|
|
/* Get the pointer to the control information */
|
|
old_mem_node = ((CHK_DYN_MEM_NODE *)ptr)-1;
|
|
|
|
/* Verify that this node is on the list before accessing it */
|
|
if (m_find_node_enable == SD_TRUE)
|
|
{
|
|
if (list_find_node (head_dyn_mem_list, old_mem_node) != SD_SUCCESS)
|
|
{
|
|
goto MEM_REALLOC_ERROR;
|
|
}
|
|
}
|
|
|
|
/* extract information from memory block header */
|
|
old_mem_ptr = old_mem_node -> chk_alloc_mem_ptr;
|
|
old_mem_size = old_mem_node -> chk_alloc_mem_size;
|
|
|
|
if (old_mem_ptr != ptr) /* verify that the ptr passed in matches */
|
|
{
|
|
MEM_REALLOC_ERROR :
|
|
MEMLOG_ERR2 ("\n File : %s, Line %d",
|
|
calling_file, calling_line);
|
|
MEMLOG_CERR1 (
|
|
"Invalid realloc (%08lx)",ptr);
|
|
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return (ptr); /* just hope realloc was for smaller */
|
|
}
|
|
|
|
/* Update memory allocation statistics parameters */
|
|
chk_curr_mem_count--; /* update the node count*/
|
|
chk_curr_mem_size -= old_mem_size; /* update the mem size */
|
|
|
|
|
|
/* Check for 'no realloc smaller' option */
|
|
/* This is controlled either by compile time define or by variable */
|
|
/* If new size is less than old size, just don't use the system realloc */
|
|
|
|
no_realloc = SD_FALSE;
|
|
|
|
#if defined(NO_REALLOC_SMALLER)
|
|
if (size <= (ST_UINT) old_mem_node -> chk_alloc_mem_size)
|
|
{
|
|
no_realloc = SD_TRUE;
|
|
}
|
|
#else
|
|
if (m_no_realloc_smaller)
|
|
{
|
|
if (size <= (ST_UINT) old_mem_node -> chk_alloc_mem_size)
|
|
{
|
|
no_realloc = SD_TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (no_realloc)
|
|
new_mem_node = old_mem_node; /* Use original buffer. */
|
|
else
|
|
{
|
|
/* invalidate the old block */
|
|
old_mem_node->chk_alloc_mem_ptr = NULL;
|
|
|
|
/* remove the old memory block from the mem_chk system */
|
|
list_unlink ((ST_VOID **)&head_dyn_mem_list, old_mem_node); /* unlink the old node */
|
|
|
|
/* Use the system realloc to get the new pointer */
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
if (m_mem_crt_debug)
|
|
new_mem_node = (CHK_DYN_MEM_NODE *)
|
|
_realloc_dbg ((ST_VOID *) old_mem_node, size + mem_overhead, _NORMAL_BLOCK,
|
|
calling_file, calling_line);
|
|
else
|
|
new_mem_node = (CHK_DYN_MEM_NODE *)
|
|
realloc ((ST_VOID *) old_mem_node, size + mem_overhead);
|
|
#else
|
|
new_mem_node = (CHK_DYN_MEM_NODE *)
|
|
realloc ((ST_VOID *) old_mem_node, size + mem_overhead);
|
|
#endif
|
|
|
|
if (new_mem_node == NULL)
|
|
{
|
|
if (!(new_mem_node = (CHK_DYN_MEM_NODE *)
|
|
(*r_memerr_fun)((ST_VOID *) old_mem_node,
|
|
size + mem_overhead)))
|
|
{
|
|
MEMLOG_ERR0 ("WARNING : Returning NULL Pointer");
|
|
MEMLOG_CALLSTACK (NULL);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return( NULL ); /* if we can't get any back we return a NULL */
|
|
}
|
|
}
|
|
|
|
/* Now add this element to the allocation control list */
|
|
list_add_first ((ST_VOID **)&head_dyn_mem_list, new_mem_node);
|
|
}
|
|
|
|
/* Now we have a new memory block, initialize the mem_chk header and */
|
|
/* put on the active list */
|
|
new_mem_node -> chk_alloc_mem_size = size;/* update the header */
|
|
new_mem_node -> chk_alloc_mem_ptr = (ST_VOID *)(new_mem_node+1);
|
|
|
|
new_mem_node->file = (ST_CHAR *)calling_file;
|
|
new_mem_node->line = calling_line;
|
|
|
|
/* Initialize the overwrite value */
|
|
set_overwrite_value (new_mem_node);
|
|
|
|
/* Update memory allocation statistics parameters */
|
|
chk_curr_mem_size += size; /* add the new size */
|
|
chk_curr_mem_count++; /* update the node count*/
|
|
if (chk_curr_mem_size > chk_max_mem_allocated)
|
|
{
|
|
chk_max_mem_allocated = chk_curr_mem_size;
|
|
if (m_auto_hw_log)
|
|
dyn_mem_ptr_status ();
|
|
}
|
|
/* log allocation info, if enabled */
|
|
MEMLOG_REALLOC3 ("chk_realloc : ptr = %08lx, size = %05u, ptr = %08lx",
|
|
ptr,size, (ST_VOID *)(new_mem_node+1));
|
|
if (calling_line != -1)
|
|
{
|
|
MEMLOG_CREALLOC2 ("File : %s. Line %d",
|
|
calling_file,
|
|
calling_line);
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return ((ST_VOID *)(new_mem_node+1));
|
|
}
|
|
else /* !m_mem_debug_saved */
|
|
return (_nd_chk_realloc (ptr, size));
|
|
}
|
|
#endif /* DEBUG_SISCO */
|
|
|
|
/************************************************************************/
|
|
/* nd_chk_realloc */
|
|
/* This function is called if (!DEBUG_SISCO) OR (!m_mem_debug_saved). */
|
|
/************************************************************************/
|
|
#ifdef DEBUG_SISCO /* Use "static" for DEBUG, so user can't call. */
|
|
static ST_VOID *_nd_chk_realloc (ST_VOID *ptr, ST_UINT size)
|
|
#else
|
|
ST_VOID *nd_chk_realloc (ST_VOID *ptr, ST_UINT size)
|
|
#endif
|
|
{
|
|
CHK_DYN_MEM_NODE_NDEBUG *old_mem_node;
|
|
CHK_DYN_MEM_NODE_NDEBUG *new_mem_node;
|
|
ST_BOOLEAN no_realloc;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
/* Get the pointer to the control information */
|
|
old_mem_node = ((CHK_DYN_MEM_NODE_NDEBUG *)ptr)-1;
|
|
|
|
/* Check for 'no realloc smaller' option */
|
|
/* This is controlled either by compile time define or by variable */
|
|
/* If new size is less than old size, just don't use the system realloc */
|
|
|
|
no_realloc = SD_FALSE;
|
|
|
|
#if defined(NO_REALLOC_SMALLER)
|
|
if (size <= (ST_UINT) old_mem_node -> chk_alloc_mem_size)
|
|
{
|
|
no_realloc = SD_TRUE;
|
|
}
|
|
#else
|
|
if (m_no_realloc_smaller)
|
|
{
|
|
if (size <= (ST_UINT) old_mem_node -> chk_alloc_mem_size)
|
|
{
|
|
no_realloc = SD_TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (no_realloc)
|
|
new_mem_node = old_mem_node; /* Use original buffer. */
|
|
else
|
|
{
|
|
/* Use the system realloc to get the new pointer */
|
|
if ((new_mem_node = (CHK_DYN_MEM_NODE_NDEBUG *)
|
|
realloc ((ST_VOID *) old_mem_node,
|
|
size + sizeof (CHK_DYN_MEM_NODE_NDEBUG))) == NULL)
|
|
{
|
|
if (!(new_mem_node =
|
|
(CHK_DYN_MEM_NODE_NDEBUG *) (*r_memerr_fun)((ST_VOID *) old_mem_node,
|
|
size + sizeof (CHK_DYN_MEM_NODE_NDEBUG))))
|
|
{
|
|
return( NULL ); /* if we can't get any back we return a NULL */
|
|
}
|
|
}
|
|
}
|
|
|
|
new_mem_node -> chk_alloc_mem_size = size; /* update the header */
|
|
return ((ST_VOID *)(new_mem_node+1));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* x_chk_free */
|
|
/************************************************************************/
|
|
|
|
#if defined(DEBUG_SISCO)
|
|
ST_VOID x_chk_free (ST_VOID *del_mem_ptr,
|
|
SD_CONST ST_CHAR *SD_CONST calling_file,
|
|
SD_CONST ST_INT calling_line)
|
|
{
|
|
CHK_DYN_MEM_NODE *chk_mem_node;
|
|
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
|
|
/* Do linked list && overwrite checks, if enabled */
|
|
if (m_check_list_enable)
|
|
check_mem_list (); /* check linked list. Works for all systems. */
|
|
|
|
/* Perform heap validation, if enabled and the system supports it */
|
|
#if defined(DEBUG_SISCO) && defined (MSOFT_HEAP_CHECK)
|
|
if (m_heap_check_enable)
|
|
msoft_heap_check (0); /* do not print the heap! */
|
|
#endif
|
|
|
|
/* log allocation info, if enabled */
|
|
MEMLOG_FREE1 ("chk_free : ptr = %08lx",del_mem_ptr);
|
|
|
|
if (calling_line != -1)
|
|
{
|
|
MEMLOG_CFREE2 ("File : %s. Line %d",
|
|
calling_file,
|
|
calling_line);
|
|
}
|
|
|
|
/* verify that a non-NULL pointer was passed in */
|
|
if (!del_mem_ptr)
|
|
{
|
|
goto MEM_FREE_ERROR;
|
|
}
|
|
|
|
/* Get the pointer to the control information */
|
|
chk_mem_node = ((CHK_DYN_MEM_NODE *)del_mem_ptr)-1;
|
|
|
|
/* Verify that this node is on the list before accessing it */
|
|
if (m_find_node_enable == SD_TRUE)
|
|
{
|
|
if (list_find_node (head_dyn_mem_list, chk_mem_node) != SD_SUCCESS)
|
|
{
|
|
goto MEM_FREE_ERROR;
|
|
}
|
|
}
|
|
|
|
/* verify that the pointer matches the expected pointer */
|
|
if (chk_mem_node->chk_alloc_mem_ptr == del_mem_ptr)
|
|
{
|
|
if (check_overwrite (chk_mem_node))
|
|
{
|
|
MEMLOG_ERR0 ("Memory overwrite at end of buffer detected");
|
|
MEMLOG_CERR5 (
|
|
"Node = %lx, Prev = %lx, Next = %lx, Len = %u, Curr = %lx",
|
|
chk_mem_node,
|
|
chk_mem_node->chk_mem_node_link.prev,
|
|
chk_mem_node->chk_mem_node_link.next,
|
|
chk_mem_node->chk_alloc_mem_size,
|
|
chk_mem_node->chk_alloc_mem_ptr);
|
|
MEMLOG_CHERR (chk_mem_node->chk_alloc_mem_size +
|
|
sizeof (CHK_DYN_MEM_NODE) +
|
|
m_num_pad_bytes, chk_mem_node);
|
|
|
|
/* Take care of this memory block */
|
|
chk_mem_node->chk_alloc_mem_ptr = NULL; /* invalidate the block */
|
|
chk_curr_mem_size -= chk_mem_node -> chk_alloc_mem_size;
|
|
chk_curr_mem_count--;
|
|
list_unlink ((ST_VOID **)&head_dyn_mem_list, chk_mem_node);
|
|
|
|
MEMLOG_CERR2 ("Pointer was allocated at file: %s, line %d ",
|
|
chk_mem_node->file,chk_mem_node->line);
|
|
goto MEM_FREE_ERROR2; /* print the call stack */
|
|
}
|
|
else /* This is a good free, do it! */
|
|
{
|
|
chk_mem_node->chk_alloc_mem_ptr = NULL; /* invalidate the block */
|
|
chk_curr_mem_size -= chk_mem_node -> chk_alloc_mem_size;
|
|
chk_curr_mem_count--;
|
|
list_unlink ((ST_VOID **)&head_dyn_mem_list, chk_mem_node);
|
|
|
|
/* Fill memory with garbage before freeing it */
|
|
#ifdef MEM_FILL_CONTROL
|
|
if (m_fill_en)
|
|
memset (chk_mem_node, m_fill_byte,
|
|
chk_mem_node->chk_alloc_mem_size +
|
|
sizeof (CHK_DYN_MEM_NODE));
|
|
#else
|
|
if (m_fill_en)
|
|
memset ((ST_CHAR *) chk_mem_node + sizeof (CHK_DYN_MEM_NODE),
|
|
m_fill_byte,
|
|
chk_mem_node->chk_alloc_mem_size);
|
|
#endif
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
if (m_mem_crt_debug)
|
|
_free_dbg ((ST_VOID *)chk_mem_node, _NORMAL_BLOCK);
|
|
else
|
|
free ((ST_VOID *)chk_mem_node);
|
|
#else
|
|
free ((ST_VOID *)chk_mem_node);
|
|
#endif
|
|
}
|
|
} /* end if pointer matched expected */
|
|
else /* Whoops, free error */
|
|
{
|
|
if (chk_debug_en & MEM_LOG_ERR)
|
|
{
|
|
MEM_FREE_ERROR :
|
|
|
|
MEMLOG_ERR1 (
|
|
"Invalid Free (%08lx)",del_mem_ptr);
|
|
|
|
MEM_FREE_ERROR2 :
|
|
MEMLOG_CERR2 ("Free call made from file : %s, Line %d ",
|
|
calling_file,
|
|
calling_line);
|
|
}
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
}
|
|
|
|
/* Do linked list && overwrite checks, if enabled */
|
|
if (m_check_list_enable)
|
|
check_mem_list (); /* check linked list. Works for all systems. */
|
|
|
|
/* Perform heap validation, if enabled and the system supports it */
|
|
#if defined(DEBUG_SISCO) && defined (MSOFT_HEAP_CHECK)
|
|
if (m_heap_check_enable)
|
|
msoft_heap_check (0); /* do not print the heap! */
|
|
#endif
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
else /* !m_mem_debug_saved */
|
|
_nd_chk_free (del_mem_ptr);
|
|
}
|
|
#endif /* DEBUG_SISCO */
|
|
|
|
|
|
/************************************************************************/
|
|
/* nd_chk_free */
|
|
/* This function is called if (!DEBUG_SISCO) OR (!m_mem_debug_saved). */
|
|
/************************************************************************/
|
|
#ifdef DEBUG_SISCO /* Use "static" for DEBUG, so user can't call. */
|
|
static ST_VOID _nd_chk_free (ST_VOID *del_mem_ptr)
|
|
#else
|
|
ST_VOID nd_chk_free (ST_VOID *del_mem_ptr)
|
|
#endif
|
|
{
|
|
/* Verify mem_check tools have been initialized, do it if not */
|
|
if (!mem_chk_initialized)
|
|
init_mem_chk ();
|
|
|
|
/* Extra () helps some "free" macros work. */
|
|
free ((((CHK_DYN_MEM_NODE_NDEBUG *)del_mem_ptr)-1));
|
|
}
|
|
|
|
#if defined(DEBUG_SISCO)
|
|
/************************************************************************/
|
|
/* x_chk_strdup */
|
|
/************************************************************************/
|
|
|
|
ST_CHAR *x_chk_strdup (ST_CHAR *str,
|
|
SD_CONST ST_CHAR *SD_CONST file,
|
|
SD_CONST ST_INT line)
|
|
{
|
|
ST_CHAR *new_str;
|
|
|
|
new_str = (ST_CHAR *) x_chk_malloc (strlen (str) + 1, file, line);
|
|
strcpy (new_str, str);
|
|
return (new_str);
|
|
}
|
|
|
|
#else /* !DEBUG_SISCO */
|
|
/************************************************************************/
|
|
/* nd_chk_strdup */
|
|
/************************************************************************/
|
|
|
|
ST_CHAR *nd_chk_strdup (ST_CHAR *str)
|
|
{
|
|
ST_CHAR *new_str;
|
|
|
|
new_str = (ST_CHAR *) nd_chk_malloc (strlen (str) + 1);
|
|
strcpy (new_str, str);
|
|
return (new_str);
|
|
}
|
|
#endif /* !DEBUG_SISCO */
|
|
|
|
/***************************************************************************/
|
|
/***************************************************************************/
|
|
/* dyn_mem_ptr_status */
|
|
/***************************************************************************/
|
|
|
|
ST_VOID dyn_mem_ptr_status ()
|
|
{
|
|
#ifdef DEBUG_SISCO
|
|
dyn_mem_ptr_status2 (NULL);
|
|
#endif
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/* dyn_mem_ptr_status2 */
|
|
/* This function will log all nodes up to marker_ptr node and return */
|
|
/* count of logged nodes. If market_ptr is NULL the function will log all */
|
|
/* memory nodes. */
|
|
/***************************************************************************/
|
|
|
|
ST_UINT dyn_mem_ptr_status2 (ST_VOID *marker_ptr)
|
|
{
|
|
ST_UINT logged_count = 0;
|
|
#ifdef DEBUG_SISCO
|
|
CHK_DYN_MEM_NODE *chk_mem_node;
|
|
ST_UINT32 count = 1;
|
|
ST_INT line = 1;
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
chk_mem_node = head_dyn_mem_list;
|
|
MEMLOG_LF ();
|
|
if (marker_ptr)
|
|
{
|
|
MEMLOG_DUMP0 ("DYNAMIC MEMORY POINTER TABLE ABOVE MARKER\n"
|
|
"----------------------------------------- ");
|
|
}
|
|
else
|
|
{
|
|
MEMLOG_DUMP0 ("DYNAMIC MEMORY POINTER TABLE\n"
|
|
"---------------------------- ");
|
|
}
|
|
while (count <= chk_curr_mem_count)
|
|
{
|
|
if (chk_mem_node == NULL)
|
|
{
|
|
MEMLOG_CDUMP0 ("Dump halted due to NULL pointer. Table corrupted.");
|
|
break; /* Break out of loop. */
|
|
}
|
|
if (marker_ptr && chk_mem_node->chk_alloc_mem_ptr == marker_ptr)
|
|
break;
|
|
++logged_count;
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
{
|
|
int req_num = -1;
|
|
_CrtIsMemoryBlock(chk_mem_node,
|
|
chk_mem_node->chk_alloc_mem_size + mem_overhead,
|
|
&req_num, NULL, NULL);
|
|
MEMLOG_CDUMP5 ("Ptr %08lx Size % 5u File : %-12s #%04d {%04d}",
|
|
chk_mem_node -> chk_alloc_mem_ptr,
|
|
chk_mem_node -> chk_alloc_mem_size,
|
|
chk_mem_node->file,
|
|
chk_mem_node->line,
|
|
req_num);
|
|
}
|
|
#else
|
|
MEMLOG_CDUMP4 ("Ptr %08lx Size % 5u File : %-12s #%04d",
|
|
chk_mem_node -> chk_alloc_mem_ptr,
|
|
chk_mem_node -> chk_alloc_mem_size,
|
|
chk_mem_node->file,
|
|
chk_mem_node->line);
|
|
#endif
|
|
|
|
chk_mem_node = (CHK_DYN_MEM_NODE *)
|
|
chk_mem_node -> chk_mem_node_link.next;
|
|
count++;
|
|
|
|
line++;
|
|
if (line > 10)
|
|
{
|
|
MEMLOG_PAUSE ("---- More Follows Press any key ----");
|
|
line = 1;
|
|
}
|
|
}
|
|
MEMLOG_CDUMP0 ("---- END OF MEMORY POINTER TABLE ----------");
|
|
|
|
MEMLOG_CDUMP1 ("Total number of allocated pointers: %lu",
|
|
(ST_ULONG) chk_curr_mem_count);
|
|
MEMLOG_CDUMP1 ("Total amount of memory allocated: %lu bytes ",
|
|
(ST_ULONG) chk_curr_mem_size);
|
|
MEMLOG_CDUMP1 ("Maximum number of pointers allocated: %lu",
|
|
(ST_ULONG) chk_max_dyn_mem_ptrs);
|
|
MEMLOG_CDUMP1 ("Maximum amount of memory allocated: %lu bytes",
|
|
(ST_ULONG) chk_max_mem_allocated);
|
|
MEMLOG_PAUSE ("");
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
#endif /* end of DEBUG_SISCO */
|
|
return (logged_count);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/* dyn_mem_ptr_statistics */
|
|
/***************************************************************************/
|
|
|
|
ST_VOID dyn_mem_ptr_statistics (ST_BOOLEAN log_to_screen)
|
|
{
|
|
#ifdef DEBUG_SISCO
|
|
CHK_DYN_MEM_NODE *chk_mem_node;
|
|
ST_UINT32 count = 1;
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
chk_mem_node = head_dyn_mem_list;
|
|
if ( log_to_screen == SD_TRUE )
|
|
{
|
|
#ifndef _WINDOWS
|
|
printf("\nDYNAMIC MEMORY POINTER TABLE ");
|
|
printf("\n----------------------------- ");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
MEMLOG_LF ();
|
|
MEMLOG_DUMP0 ("DYNAMIC MEMORY POINTER TABLE ");
|
|
MEMLOG_CDUMP0 ("----------------------------- ");
|
|
}
|
|
while (count <= chk_curr_mem_count)
|
|
{
|
|
chk_mem_node = (CHK_DYN_MEM_NODE *)
|
|
chk_mem_node -> chk_mem_node_link.next;
|
|
count++;
|
|
}
|
|
|
|
if ( log_to_screen == SD_TRUE )
|
|
{
|
|
#if !defined(_WINDOWS) || defined(_WIN32)
|
|
printf ("\nTotal number of allocated pointers: %lu",
|
|
(ST_ULONG) chk_curr_mem_count);
|
|
printf ("\nTotal amount of memory allocated: %lu bytes ",
|
|
(ST_ULONG) chk_curr_mem_size);
|
|
printf ("\nMaximum number of pointers allocated: %lu",
|
|
(ST_ULONG) chk_max_dyn_mem_ptrs);
|
|
printf ("\nMaximum amount of memory allocated: %lu bytes",
|
|
(ST_ULONG) chk_max_mem_allocated);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
MEMLOG_CDUMP1 ("Total number of allocated pointers: %lu",
|
|
(ST_ULONG) chk_curr_mem_count);
|
|
MEMLOG_CDUMP1 ("Total amount of memory allocated: %lu bytes ",
|
|
(ST_ULONG) chk_curr_mem_size);
|
|
MEMLOG_CDUMP1 ("Maximum number of pointers allocated: %lu",
|
|
(ST_ULONG) chk_max_dyn_mem_ptrs);
|
|
MEMLOG_CDUMP1 ("Maximum amount of memory allocated: %lu bytes",
|
|
(ST_ULONG) chk_max_mem_allocated);
|
|
MEMLOG_PAUSE ("");
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
#endif /* end of DEBUG_SISCO */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/************************************************************************/
|
|
/* chk_hp */
|
|
/* Perform system specific heap validation */
|
|
/************************************************************************/
|
|
|
|
ST_RET chk_hp (ST_INT16 prt_mask, ST_CHAR *file, ST_INT line)
|
|
{
|
|
ST_RET ret;
|
|
|
|
ret = SD_SUCCESS;
|
|
|
|
#if defined(DEBUG_SISCO) && defined (MSOFT_HEAP_CHECK)
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
if (ret = msoft_heap_check (prt_mask))
|
|
{
|
|
MEMLOG_ERR2 ("\nFILE : %s, LINE %d",file,line);
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
#endif
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* msoft_heap_check */
|
|
/* Perform Microsoft specific heap validation */
|
|
/* Also sets all unused heap to 0x55 */
|
|
/************************************************************************/
|
|
|
|
ST_RET msoft_heap_check (ST_INT16 prt_mask)
|
|
{
|
|
#if defined(DEBUG_SISCO) && defined (MSOFT_HEAP_CHECK)
|
|
struct _heapinfo entry;
|
|
ST_INT i;
|
|
ST_INT ret;
|
|
ST_BOOLEAN error;
|
|
ST_INT32 total_size;
|
|
ST_INT num_ptrs;
|
|
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
entry._pentry = NULL; /* start at the top of the list */
|
|
error = SD_FALSE;
|
|
total_size = 0;
|
|
num_ptrs = 0;
|
|
for (i = 0; SD_TRUE; ++i)
|
|
{
|
|
ret = _heapwalk (&entry);
|
|
switch (ret)
|
|
{
|
|
case _HEAPBADPTR :
|
|
MEMLOG_ERR0 ("BAD HEAP : POINTER OUTSIDE HEAP");
|
|
error = SD_TRUE;
|
|
break;
|
|
case _HEAPBADBEGIN :
|
|
MEMLOG_ERR0 ("BAD HEAP : INITIAL ENTRY");
|
|
error = SD_TRUE;
|
|
break;
|
|
case _HEAPBADNODE :
|
|
MEMLOG_ERR0 ("BAD HEAP : BAD NODE ");
|
|
error = SD_TRUE;
|
|
break;
|
|
}
|
|
|
|
if (prt_mask & DEBUG_HEAP_ENTRY)
|
|
{
|
|
if (ret == _HEAPEMPTY)
|
|
{
|
|
MEMLOG_DUMP0 ("Heap Empty");
|
|
}
|
|
else if (ret == _HEAPEND)
|
|
{
|
|
MEMLOG_DUMP0 ("End Of Heap");
|
|
}
|
|
else
|
|
{
|
|
MEMLOG_CDUMP1 (" Heap Entry %d :",i);
|
|
MEMLOG_CDUMP1 (" Pointer : %08lX",entry._pentry);
|
|
MEMLOG_CDUMP1 (" Size (decimal) : %d",entry._size);
|
|
MEMLOG_CDUMP1 (" Use Flag : %s",
|
|
entry._useflag == _USEDENTRY ? "USED" : "FREE");
|
|
num_ptrs++;
|
|
total_size += entry._size;
|
|
}
|
|
|
|
MEMLOG_PAUSE ("Hit any key to continue - ");
|
|
}
|
|
|
|
if (ret == _HEAPEND || ret == _HEAPEMPTY || error)
|
|
break;
|
|
}
|
|
|
|
if (prt_mask & DEBUG_HEAP_SUM)
|
|
{
|
|
MEMLOG_DUMP1 ("Total # Pointers : %d",num_ptrs);
|
|
MEMLOG_CDUMP1 ("Total memory malloc'd : %ld",total_size);
|
|
MEMLOG_PAUSE ("Hit any key to continue - ");
|
|
}
|
|
|
|
_heapset ('\x55'); /* write all unused memory with 55's */
|
|
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return (SD_FALSE);
|
|
#elif defined(DEBUG_SISCO) && defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
return _CrtCheckMemory () ? SD_FALSE : SD_TRUE;
|
|
#else
|
|
return (SD_FALSE);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/************************************************************************/
|
|
/* chk_alloc_ptr */
|
|
/************************************************************************/
|
|
|
|
ST_RET chk_alloc_ptr (ST_VOID *mem_ptr)
|
|
{
|
|
#ifdef DEBUG_SISCO
|
|
CHK_DYN_MEM_NODE *chk_mem_node;
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
/* verify that a non-NULL pointer was passed in */
|
|
if (!mem_ptr)
|
|
{
|
|
if (chk_debug_en & MEM_LOG_ERR)
|
|
{
|
|
MEMLOG_ERR0 ("NULL pointer in chk_alloc_ptr");
|
|
goto MEM_PTR_CHK_ERROR;
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return(SD_FAILURE);
|
|
}
|
|
|
|
/* verify that the pointer matches the expected pointer */
|
|
chk_mem_node = ((CHK_DYN_MEM_NODE *)mem_ptr)-1;
|
|
|
|
/* Verify that this node is on the list before accessing it */
|
|
if (list_find_node (head_dyn_mem_list, chk_mem_node) != SD_SUCCESS)
|
|
{
|
|
if (chk_debug_en & MEM_LOG_ERR)
|
|
{
|
|
MEMLOG_ERR0 (" chk_alloc_ptr - pointer not on list");
|
|
goto MEM_PTR_CHK_ERROR;
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return(SD_FAILURE);
|
|
}
|
|
|
|
if (chk_mem_node->chk_alloc_mem_ptr == mem_ptr)
|
|
{
|
|
if (chk_mem_node->overwrite_prev_detected == SD_FALSE)
|
|
{
|
|
if (check_overwrite (chk_mem_node))
|
|
{
|
|
MEMLOG_ERR0 ("Memory overwrite at end of buffer detected");
|
|
chk_mem_node->overwrite_prev_detected=SD_TRUE;
|
|
MEMLOG_CERR5 (
|
|
"Node = %lx, Prev = %lx, Next = %lx, Len = %u, Curr = %lx",
|
|
chk_mem_node,
|
|
chk_mem_node->chk_mem_node_link.prev,
|
|
chk_mem_node->chk_mem_node_link.next,
|
|
chk_mem_node->chk_alloc_mem_size,
|
|
chk_mem_node->chk_alloc_mem_ptr);
|
|
MEMLOG_CERR2 ("Pointer was allocated at file: %s, line %d ",
|
|
chk_mem_node->file,chk_mem_node->line);
|
|
MEMLOG_CHERR (chk_mem_node->chk_alloc_mem_size +
|
|
sizeof (CHK_DYN_MEM_NODE) +
|
|
m_num_pad_bytes, chk_mem_node);
|
|
goto MEM_PTR_CHK_ERROR2;
|
|
}
|
|
} /* end if overwrite not detected for this node */
|
|
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
if (_CrtIsMemoryBlock (chk_mem_node, chk_mem_node->chk_alloc_mem_size + mem_overhead,
|
|
NULL, NULL, NULL) == FALSE)
|
|
{
|
|
MEMLOG_ERR0 ("Buffer not a valid memory block");
|
|
MEMLOG_CERR5 (
|
|
"Node = %lx, Prev = %lx, Next = %lx, Len = %u, Curr = %lx",
|
|
chk_mem_node,
|
|
chk_mem_node->chk_mem_node_link.prev,
|
|
chk_mem_node->chk_mem_node_link.next,
|
|
chk_mem_node->chk_alloc_mem_size,
|
|
chk_mem_node->chk_alloc_mem_ptr);
|
|
MEMLOG_CERR2 ("Pointer was allocated at file: %s, line %d ",
|
|
chk_mem_node->file,chk_mem_node->line);
|
|
MEMLOG_CHERR (chk_mem_node->chk_alloc_mem_size +
|
|
sizeof (CHK_DYN_MEM_NODE) +
|
|
m_num_pad_bytes, chk_mem_node);
|
|
goto MEM_PTR_CHK_ERROR2;
|
|
}
|
|
#endif
|
|
}
|
|
else /* Pointer does not match header */
|
|
{
|
|
MEM_PTR_CHK_ERROR :
|
|
|
|
MEMLOG_ERR1 ("Pointer Does Not Exist (%08lx)",mem_ptr);
|
|
|
|
MEM_PTR_CHK_ERROR2 :
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return(SD_FAILURE);
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
#endif
|
|
return(SD_SUCCESS);
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* check_mem_list */
|
|
/************************************************************************/
|
|
|
|
ST_VOID check_mem_list ()
|
|
{
|
|
#ifdef DEBUG_SISCO
|
|
CHK_DYN_MEM_NODE *node;
|
|
CHK_DYN_MEM_NODE *prev;
|
|
CHK_DYN_MEM_NODE *next;
|
|
ST_INT len;
|
|
ST_VOID *curr;
|
|
ST_UINT32 j;
|
|
|
|
if (m_mem_debug_saved)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
if ((node = head_dyn_mem_list) == NULL)
|
|
{
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return; /* list empty. Nothing to check */
|
|
}
|
|
for (j = 0; j < chk_max_dyn_mem_ptrs; j++)
|
|
{
|
|
/* should break out when j = chk_curr_mem_count */
|
|
prev = (CHK_DYN_MEM_NODE *) node->chk_mem_node_link.prev;
|
|
next = (CHK_DYN_MEM_NODE *) node->chk_mem_node_link.next;
|
|
len = node->chk_alloc_mem_size;
|
|
curr = node->chk_alloc_mem_ptr;
|
|
|
|
/* check ptr to this node */
|
|
if (curr != (ST_VOID *) (node + 1))
|
|
{
|
|
MEMLOG_ERR1 ("Current node pointer corrupted on node #%d", j);
|
|
MEMLOG_CERR5 (
|
|
"Node = %lx, Prev = %lx, Next = %lx, Len = %u, Curr = %lx",
|
|
node, prev, next, len, curr);
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
}
|
|
|
|
/* check link list ptrs */
|
|
if (node != (CHK_DYN_MEM_NODE *) next->chk_mem_node_link.prev)
|
|
{
|
|
MEMLOG_ERR1 ("\nLinked list corrupted at node #%d", j);
|
|
MEMLOG_CERR6 (
|
|
"Node=%lx, Prev=%lx, Next=%lx, Len=%5u, Curr=%lx, Next node's prev=%lx",
|
|
node, prev, next, len, curr, next->chk_mem_node_link.prev);
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
}
|
|
|
|
/* Check for buffer overwrite */
|
|
if (check_overwrite (node))
|
|
{
|
|
if(node->overwrite_prev_detected==SD_FALSE)
|
|
{
|
|
MEMLOG_ERR0 ("Memory overwrite at end of buffer detected");
|
|
MEMLOG_CERR5 (
|
|
"Node = %lx, Prev = %lx, Next = %lx, Len = %u, Curr = %lx",
|
|
node, prev, next, len, curr);
|
|
MEMLOG_CERR2 ("Pointer was allocated at file: %s, line %d ",
|
|
node->file,node->line);
|
|
MEMLOG_CHERR (node->chk_alloc_mem_size +
|
|
sizeof (CHK_DYN_MEM_NODE) +
|
|
m_num_pad_bytes, node);
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
node->overwrite_prev_detected=SD_TRUE;
|
|
}
|
|
}
|
|
#if defined(MEMCHK_WIN32_CRT_DEBUG)
|
|
else
|
|
{
|
|
if (_CrtIsMemoryBlock (node, node->chk_alloc_mem_size + mem_overhead,
|
|
NULL, NULL, NULL) == FALSE)
|
|
{
|
|
MEMLOG_ERR0 ("Buffer not a valid memory block");
|
|
MEMLOG_CERR5 (
|
|
"Node = %lx, Prev = %lx, Next = %lx, Len = %u, Curr = %lx",
|
|
node,
|
|
node->chk_mem_node_link.prev,
|
|
node->chk_mem_node_link.next,
|
|
node->chk_alloc_mem_size,
|
|
node->chk_alloc_mem_ptr);
|
|
MEMLOG_CERR2 ("Pointer was allocated at file: %s, line %d ",
|
|
node->file,node->line);
|
|
MEMLOG_CHERR (node->chk_alloc_mem_size +
|
|
sizeof (CHK_DYN_MEM_NODE) +
|
|
m_num_pad_bytes, node);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (next == head_dyn_mem_list) /* is this last node on list? */
|
|
break;
|
|
|
|
node = next; /* point to next node in linked list */
|
|
} /* end "for" */
|
|
|
|
if (j >= chk_max_dyn_mem_ptrs)
|
|
{
|
|
MEMLOG_ERR1 (
|
|
"Last node (Node #%d) does not point back to first.", j - 1);
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
}
|
|
else if (j + 1 != chk_curr_mem_count)
|
|
{
|
|
MEMLOG_CERR0 ("Linked list current count corrupted.");
|
|
MEMLOG_CERR2 ("Count = %lu, Should be = %lu.",
|
|
(ST_ULONG) chk_curr_mem_count, (ST_ULONG) (j + 1));
|
|
MEMLOG_CALLSTACK (NULL);
|
|
MEMLOG_PAUSEERR ("");
|
|
if (mem_chk_err)
|
|
(*mem_chk_err)();
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
#endif /* DEBUG_SISCO */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* check_overwrite */
|
|
/************************************************************************/
|
|
|
|
#ifdef DEBUG_SISCO
|
|
static ST_RET check_overwrite (CHK_DYN_MEM_NODE *node)
|
|
{
|
|
ST_CHAR *bptr;
|
|
ST_CHAR *eptr;
|
|
ST_INT i;
|
|
|
|
/* Get a pointer to the byte after the user's data */
|
|
bptr = (ST_CHAR *) (node +1);
|
|
bptr += node->chk_alloc_mem_size;
|
|
eptr = bptr + m_num_pad_bytes;
|
|
|
|
/* Verify the signature */
|
|
i = 0;
|
|
while (bptr < eptr)
|
|
{
|
|
if (*(bptr++) != m_pad_string[i])
|
|
return (SD_TRUE); /* Overwrite detected, return the error */
|
|
|
|
if (++i >= m_num_pad_bytes) /* if we have wrapped the string */
|
|
i = 0;
|
|
}
|
|
|
|
/* All is OK with the end of this buffer */
|
|
return (SD_FALSE);
|
|
}
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* set_overwrite_value */
|
|
/************************************************************************/
|
|
|
|
#ifdef DEBUG_SISCO
|
|
static ST_VOID set_overwrite_value (CHK_DYN_MEM_NODE *node)
|
|
{
|
|
ST_CHAR *bptr;
|
|
ST_CHAR *eptr;
|
|
ST_INT i;
|
|
|
|
/* Get a pointer to the byte after the user's data */
|
|
bptr = (ST_CHAR *)(node+1);
|
|
bptr += node->chk_alloc_mem_size;
|
|
eptr = bptr + m_num_pad_bytes;
|
|
|
|
/* Set the signature */
|
|
i = 0;
|
|
while (bptr < eptr)
|
|
{
|
|
*(bptr++) = m_pad_string[i];
|
|
if (++i >= m_num_pad_bytes) /* if we have wrapped the string */
|
|
i = 0;
|
|
}
|
|
|
|
node->overwrite_prev_detected=SD_FALSE;
|
|
}
|
|
#endif
|
|
|
|
|