--- /dev/null
+#include <stdlib.h>
+#include "codemuxlib.h"
+#include "debug.h"
+#include "queue.h"
+
+#ifdef DEBUG_MEMORY_LEAK
+
+/* Maximum length of the location string containing function, file and
+ the line number of the memory allocation part in the original
+ source code. The location info is added in front of the pointer
+ when allocating memory and return p + MAX_LOCATION_STRLEN to the
+ user */
+#define MAX_LOCATION_STRLEN 512
+
+typedef struct MemoryAllocInfo {
+ char *mi_locstr; /* location string "__FUNCTION__:__LINE__" */
+ int mi_count; /* allocated memory counts */
+ LIST_ENTRY(MemoryAllocInfo) mi_hash;
+ LIST_ENTRY(MemoryAllocInfo) mi_all;
+} MemoryAllocInfo;
+
+#define MAX_BINS 257 /* a prime number near 256 */
+static LIST_HEAD(, MemoryAllocInfo) miBins[MAX_BINS];
+static LIST_HEAD(, MemoryAllocInfo) miHead = LIST_HEAD_INITIALIZER(miHead);
+
+/*-------------------------------------------------------------------------*/
+void
+dbg_print_memtrace(void)
+{
+ MemoryAllocInfo *walk;
+
+ TRACE("memory alloc counts dump begins\n");
+ LIST_FOREACH(walk, &miHead, mi_all) {
+ TRACE("%-50s: %d\n", walk->mi_locstr, walk->mi_count);
+ }
+ TRACE("memory alloc counts dump ends\n");
+}
+/*-------------------------------------------------------------------------*/
+static void
+increase_alloc_count(char* p, const char* func,
+ const char* file, const int line)
+{
+ int bin;
+ MemoryAllocInfo* walk;
+
+#define MAX_LINE_DIGIT 7 /* million lines of code per file is way too much */
+#define LOCSTR_LENGH (strlen(func) + strlen(file) + MAX_LINE_DIGIT + 3)
+
+ if (LOCSTR_LENGH >= MAX_LOCATION_STRLEN) {
+ TRACE("over the length limit %s:%d\n", func, line);
+ FlushLogF(hdebugLog);
+ exit(-1);
+ }
+ snprintf(p, MAX_LOCATION_STRLEN, "%s:%s:%d", func, file, line);
+
+ bin = (int)(HashString(p, 0, FALSE, FALSE) % MAX_BINS);
+ LIST_FOREACH(walk, &miBins[bin], mi_hash) {
+ if (strcmp(walk->mi_locstr, p) == 0) { /* match */
+ walk->mi_count++;
+ return;
+ }
+ }
+
+ /* allocate it if not found */
+ if ((walk = (MemoryAllocInfo *)calloc(1, sizeof(MemoryAllocInfo))) == NULL) {
+ TRACE("calloc failed\n");
+ FlushLogF(hdebugLog);
+ exit(-1);
+ }
+ if ((walk->mi_locstr = strdup(p)) == NULL) {
+ TRACE("calloc failed\n");
+ FlushLogF(hdebugLog);
+ exit(-1);
+ }
+ walk->mi_count++;
+ LIST_INSERT_HEAD(&miBins[bin], walk, mi_hash);
+ LIST_INSERT_HEAD(&miHead, walk, mi_all);
+}
+/*-------------------------------------------------------------------------*/
+static void
+decrease_alloc_count(char *p, const char* func,
+ const char* file, const int line)
+{
+ int bin = (int)(HashString(p, 0, FALSE, FALSE) % MAX_BINS);
+ MemoryAllocInfo* walk;
+
+ LIST_FOREACH(walk, &miBins[bin], mi_hash) {
+ if (strcmp(walk->mi_locstr, p) == 0) { /* match */
+ walk->mi_count--;
+ if (walk->mi_count == 0) {
+ LIST_REMOVE(walk, mi_hash);
+ LIST_REMOVE(walk, mi_all);
+ free(walk->mi_locstr);
+ free(walk);
+ }
+ return;
+ }
+ }
+
+ TRACE("decrease failed %s:%s:%d\n", func, file, line);
+ FlushLogF(hdebugLog);
+ exit(-1);
+}
+/*-------------------------------------------------------------------------*/
+void *
+dbgcalloc(size_t nmemb, size_t size,
+ const char* func, const char* file, const int line)
+{
+ int msize = nmemb * size + MAX_LOCATION_STRLEN;
+ char *p;
+
+ if ((p = (char *)calloc(1, msize)) != NULL) {
+ increase_alloc_count(p, func, file, line);
+ return (void *)(p + MAX_LOCATION_STRLEN);
+ }
+ return NULL;
+}
+/*-------------------------------------------------------------------------*/
+void *
+dbgmalloc(size_t size, const char* func, const char* file, const int line)
+{
+ int msize = size + MAX_LOCATION_STRLEN;
+ char *p;
+
+ if ((p = (char *)malloc(msize)) != NULL) {
+ increase_alloc_count(p, func, file, line);
+ return (void *)(p + MAX_LOCATION_STRLEN);
+ }
+ return NULL;
+}
+/*-------------------------------------------------------------------------*/
+void *
+dbgrealloc(void *ptr, size_t size,
+ const char* func, const char* file, const int line)
+{
+ int msize = size + MAX_LOCATION_STRLEN;
+ char *p;
+
+ if (ptr != NULL) {
+ ptr -= MAX_LOCATION_STRLEN;
+ decrease_alloc_count(ptr, func, file, line);
+ }
+
+ if ((p = (char *)realloc(ptr, msize)) != NULL) {
+ increase_alloc_count(p, func, file, line);
+ return (void *)(p + MAX_LOCATION_STRLEN);
+ }
+ return NULL;
+}
+/*-------------------------------------------------------------------------*/
+char *
+dbgstrdup(const char *s, const char* func, const char* file, const int line)
+{
+ int msize = strlen(s) + 1 + MAX_LOCATION_STRLEN;
+ char *p;
+
+ if ((p = (char *)malloc(msize))) {
+ increase_alloc_count(p, func, file, line);
+ p += MAX_LOCATION_STRLEN;
+ strcpy(p, s);
+ return p;
+ }
+ return NULL;
+}
+/*-------------------------------------------------------------------------*/
+void
+dbgfree(void *ptr, const char* func, const char* file, const int line)
+{
+ /* should free the original pointer */
+ char* chptr = (char *)ptr;
+
+ chptr -= MAX_LOCATION_STRLEN;
+ decrease_alloc_count(chptr, func, file, line);
+ free(chptr);
+}
+#endif
+