/************************************************************************/ /* 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 /* 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 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