Setting tag codemux-0.1-15
[codemux.git] / debug.c
1 #include <stdlib.h>
2 #include "codemuxlib.h"
3 #include "debug.h"
4 #include "queue.h"
5
6 #ifdef DEBUG_MEMORY_LEAK
7
8 /* Maximum length of the location string containing function, file and
9    the line number of the memory allocation part in the original
10    source code. The location info is added in front of the pointer
11    when allocating memory and return p + MAX_LOCATION_STRLEN to the
12    user */
13 #define MAX_LOCATION_STRLEN 512 
14
15 typedef struct MemoryAllocInfo {
16   char *mi_locstr;             /* location string "__FUNCTION__:__LINE__" */
17   int  mi_count;               /* allocated memory counts */
18   LIST_ENTRY(MemoryAllocInfo) mi_hash;
19   LIST_ENTRY(MemoryAllocInfo) mi_all;                    
20 } MemoryAllocInfo;
21
22 #define MAX_BINS 257 /* a prime number near 256 */
23 static LIST_HEAD(, MemoryAllocInfo) miBins[MAX_BINS];
24 static LIST_HEAD(, MemoryAllocInfo) miHead = LIST_HEAD_INITIALIZER(miHead);
25
26 /*-------------------------------------------------------------------------*/
27 void 
28 dbg_print_memtrace(void)
29 {
30   MemoryAllocInfo *walk;
31
32   TRACE("memory alloc counts dump begins\n");
33   LIST_FOREACH(walk, &miHead, mi_all) {
34     TRACE("%-50s: %d\n", walk->mi_locstr, walk->mi_count);
35   }
36   TRACE("memory alloc counts dump ends\n");
37 }
38 /*-------------------------------------------------------------------------*/
39 static void 
40 increase_alloc_count(char* p, const char* func, 
41                      const char* file, const int line)
42 {
43   int bin;
44   MemoryAllocInfo* walk;
45
46 #define MAX_LINE_DIGIT 7 /* million lines of code per file is way too much */
47 #define LOCSTR_LENGH  (strlen(func) + strlen(file) + MAX_LINE_DIGIT + 3)
48
49   if (LOCSTR_LENGH >= MAX_LOCATION_STRLEN) {
50     TRACE("over the length limit %s:%d\n", func, line);
51     FlushLogF(hdebugLog);
52     exit(-1);
53   }
54   snprintf(p, MAX_LOCATION_STRLEN, "%s:%s:%d", func, file, line);
55
56   bin = (int)(HashString(p, 0, FALSE, FALSE) % MAX_BINS);
57   LIST_FOREACH(walk, &miBins[bin], mi_hash) {
58     if (strcmp(walk->mi_locstr, p) == 0) { /* match */
59       walk->mi_count++;
60       return;
61     }
62   }
63   
64   /* allocate it if not found */
65   if ((walk = (MemoryAllocInfo *)calloc(1, sizeof(MemoryAllocInfo))) == NULL) {
66     TRACE("calloc failed\n");
67     FlushLogF(hdebugLog);
68     exit(-1);
69   }
70   if ((walk->mi_locstr = strdup(p)) == NULL) {
71     TRACE("calloc failed\n");
72     FlushLogF(hdebugLog);
73     exit(-1);
74   }
75   walk->mi_count++;
76   LIST_INSERT_HEAD(&miBins[bin], walk, mi_hash);
77   LIST_INSERT_HEAD(&miHead, walk, mi_all);
78 }
79 /*-------------------------------------------------------------------------*/
80 static void
81 decrease_alloc_count(char *p, const char* func, 
82                      const char* file, const int line)
83
84   int bin = (int)(HashString(p, 0, FALSE, FALSE) % MAX_BINS);
85   MemoryAllocInfo* walk;
86
87   LIST_FOREACH(walk, &miBins[bin], mi_hash) {
88     if (strcmp(walk->mi_locstr, p) == 0) { /* match */
89       walk->mi_count--;
90       if (walk->mi_count == 0) {
91         LIST_REMOVE(walk, mi_hash);
92         LIST_REMOVE(walk, mi_all);
93         free(walk->mi_locstr);
94         free(walk);
95       }
96       return;
97     }
98   }
99
100   TRACE("decrease failed %s:%s:%d\n", func, file, line);
101   FlushLogF(hdebugLog);
102   exit(-1);
103 }
104 /*-------------------------------------------------------------------------*/
105 void *
106 dbgcalloc(size_t nmemb, size_t size, 
107           const char* func,  const char* file, const int line)
108 {
109   int msize = nmemb * size + MAX_LOCATION_STRLEN;
110   char *p;
111
112   if ((p = (char *)calloc(1, msize)) != NULL) {
113     increase_alloc_count(p, func, file, line);
114     return (void *)(p + MAX_LOCATION_STRLEN);
115   }
116   return NULL;
117 }
118 /*-------------------------------------------------------------------------*/
119 void *
120 dbgmalloc(size_t size, const char* func, const char* file, const int line)
121 {
122   int msize = size + MAX_LOCATION_STRLEN;
123   char *p;
124
125   if ((p = (char *)malloc(msize)) != NULL) {
126     increase_alloc_count(p, func, file, line);
127     return (void *)(p + MAX_LOCATION_STRLEN);
128   }
129   return NULL;
130 }
131 /*-------------------------------------------------------------------------*/
132 void *
133 dbgrealloc(void *ptr, size_t size, 
134            const char* func, const char* file, const int line)
135 {
136   int msize = size + MAX_LOCATION_STRLEN;
137   char *p;
138
139   if (ptr != NULL) {
140     ptr -= MAX_LOCATION_STRLEN;
141     decrease_alloc_count(ptr, func, file, line);
142   }
143
144   if ((p = (char *)realloc(ptr, msize)) != NULL) {
145     increase_alloc_count(p, func, file, line);
146     return (void *)(p + MAX_LOCATION_STRLEN);
147   }
148   return NULL;
149 }
150 /*-------------------------------------------------------------------------*/
151 char *
152 dbgstrdup(const char *s, const char* func, const char* file, const int line)
153 {
154   int msize = strlen(s) + 1 + MAX_LOCATION_STRLEN;
155   char *p;
156
157   if ((p = (char *)malloc(msize))) {
158     increase_alloc_count(p, func, file, line);
159     p += MAX_LOCATION_STRLEN;
160     strcpy(p, s);
161     return p;
162   }
163   return NULL;
164 }
165 /*-------------------------------------------------------------------------*/
166 void 
167 dbgfree(void *ptr, const char* func, const char* file, const int line)
168 {
169   /* should free the original pointer */
170   char* chptr = (char *)ptr;
171
172   chptr -= MAX_LOCATION_STRLEN;
173   decrease_alloc_count(chptr, func, file, line);
174   free(chptr);
175 }
176 #endif
177