]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/grep/regex/xmalloc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.bin / grep / regex / xmalloc.c
1 /* $FreeBSD$ */
2
3 /*
4   xmalloc.c - Simple malloc debugging library implementation
5
6   This software is released under a BSD-style license.
7   See the file LICENSE for details and copyright.
8
9 */
10
11 /*
12   TODO:
13    - red zones
14    - group dumps by source location
15 */
16
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <stdio.h>
20 #define XMALLOC_INTERNAL 1
21 #include "xmalloc.h"
22
23 \f
24 /*
25   Internal stuff.
26 */
27
28 typedef struct hashTableItemRec {
29   void *ptr;
30   int bytes;
31   const char *file;
32   int line;
33   const char *func;
34   struct hashTableItemRec *next;
35 } hashTableItem;
36
37 typedef struct {
38   hashTableItem **table;
39 } hashTable;
40
41 static int xmalloc_peak;
42 int xmalloc_current;
43 static int xmalloc_peak_blocks;
44 int xmalloc_current_blocks;
45 static int xmalloc_fail_after;
46
47 #define TABLE_BITS 8
48 #define TABLE_MASK ((1 << TABLE_BITS) - 1)
49 #define TABLE_SIZE (1 << TABLE_BITS)
50
51 static hashTable *
52 hash_table_new(void)
53 {
54   hashTable *tbl;
55
56   tbl = malloc(sizeof(*tbl));
57
58   if (tbl != NULL)
59     {
60       tbl->table = calloc(TABLE_SIZE, sizeof(*tbl->table));
61
62       if (tbl->table == NULL)
63         {
64           free(tbl);
65           return NULL;
66         }
67     }
68
69   return tbl;
70 }
71
72 static int
73 hash_void_ptr(void *ptr)
74 {
75   int hash;
76   int i;
77
78   /* I took this hash function just off the top of my head, I have
79      no idea whether it is bad or very bad. */
80   hash = 0;
81   for (i = 0; i < (int)sizeof(ptr)*8 / TABLE_BITS; i++)
82     {
83       hash ^= (unsigned long)ptr >> i*8;
84       hash += i * 17;
85       hash &= TABLE_MASK;
86     }
87   return hash;
88 }
89
90 static void
91 hash_table_add(hashTable *tbl, void *ptr, int bytes,
92                const char *file, int line, const char *func)
93 {
94   int i;
95   hashTableItem *item, *new;
96
97   i = hash_void_ptr(ptr);
98
99   item = tbl->table[i];
100   if (item != NULL)
101     while (item->next != NULL)
102       item = item->next;
103
104   new = malloc(sizeof(*new));
105   assert(new != NULL);
106   new->ptr = ptr;
107   new->bytes = bytes;
108   new->file = file;
109   new->line = line;
110   new->func = func;
111   new->next = NULL;
112   if (item != NULL)
113     item->next = new;
114   else
115     tbl->table[i] = new;
116
117   xmalloc_current += bytes;
118   if (xmalloc_current > xmalloc_peak)
119     xmalloc_peak = xmalloc_current;
120   xmalloc_current_blocks++;
121   if (xmalloc_current_blocks > xmalloc_peak_blocks)
122     xmalloc_peak_blocks = xmalloc_current_blocks;
123 }
124
125 static void
126 hash_table_del(hashTable *tbl, void *ptr)
127 {
128   int i;
129   hashTableItem *item, *prev;
130
131   i = hash_void_ptr(ptr);
132
133   item = tbl->table[i];
134   if (item == NULL)
135     {
136       printf("xfree: invalid ptr %p\n", ptr);
137       abort();
138     }
139   prev = NULL;
140   while (item->ptr != ptr)
141     {
142       prev = item;
143       item = item->next;
144     }
145   if (item->ptr != ptr)
146     {
147       printf("xfree: invalid ptr %p\n", ptr);
148       abort();
149     }
150
151   xmalloc_current -= item->bytes;
152   xmalloc_current_blocks--;
153
154   if (prev != NULL)
155     {
156       prev->next = item->next;
157       free(item);
158     }
159   else
160     {
161       tbl->table[i] = item->next;
162       free(item);
163     }
164 }
165
166 static hashTable *xmalloc_table = NULL;
167
168 static void
169 xmalloc_init(void)
170 {
171   if (xmalloc_table == NULL)
172     {
173       xmalloc_table = hash_table_new();
174       xmalloc_peak = 0;
175       xmalloc_peak_blocks = 0;
176       xmalloc_current = 0;
177       xmalloc_current_blocks = 0;
178       xmalloc_fail_after = -1;
179     }
180   assert(xmalloc_table != NULL);
181   assert(xmalloc_table->table != NULL);
182 }
183
184
185 \f
186 /*
187   Public API.
188 */
189
190 void
191 xmalloc_configure(int fail_after)
192 {
193   xmalloc_init();
194   xmalloc_fail_after = fail_after;
195 }
196
197 int
198 xmalloc_dump_leaks(void)
199 {
200   int i;
201   int num_leaks = 0;
202   int leaked_bytes = 0;
203   hashTableItem *item;
204
205   xmalloc_init();
206
207   for (i = 0; i < TABLE_SIZE; i++)
208     {
209       item = xmalloc_table->table[i];
210       while (item != NULL)
211         {
212           printf("%s:%d: %s: %d bytes at %p not freed\n",
213                  item->file, item->line, item->func, item->bytes, item->ptr);
214           num_leaks++;
215           leaked_bytes += item->bytes;
216           item = item->next;
217         }
218     }
219   if (num_leaks == 0)
220     printf("No memory leaks.\n");
221   else
222     printf("%d unfreed memory chuncks, total %d unfreed bytes.\n",
223            num_leaks, leaked_bytes);
224   printf("Peak memory consumption %d bytes (%.1f kB, %.1f MB) in %d blocks ",
225          xmalloc_peak, (double)xmalloc_peak / 1024,
226          (double)xmalloc_peak / (1024*1024), xmalloc_peak_blocks);
227   printf("(average ");
228   if (xmalloc_peak_blocks)
229     printf("%d", ((xmalloc_peak + xmalloc_peak_blocks / 2)
230                   / xmalloc_peak_blocks));
231   else
232     printf("N/A");
233   printf(" bytes per block).\n");
234
235   return num_leaks;
236 }
237
238 void *
239 xmalloc_impl(size_t size, const char *file, int line, const char *func)
240 {
241   void *ptr;
242
243   xmalloc_init();
244   assert(size > 0);
245
246   if (xmalloc_fail_after == 0)
247     {
248       xmalloc_fail_after = -2;
249 #if 0
250       printf("xmalloc: forced failure %s:%d: %s\n", file, line, func);
251 #endif
252       return NULL;
253     }
254   else if (xmalloc_fail_after == -2)
255     {
256       printf("xmalloc: called after failure from %s:%d: %s\n",
257              file, line, func);
258       assert(0);
259     }
260   else if (xmalloc_fail_after > 0)
261     xmalloc_fail_after--;
262
263   ptr = malloc(size);
264   if (ptr != NULL)
265     hash_table_add(xmalloc_table, ptr, (int)size, file, line, func);
266   return ptr;
267 }
268
269 void *
270 xcalloc_impl(size_t nmemb, size_t size, const char *file, int line,
271              const char *func)
272 {
273   void *ptr;
274
275   xmalloc_init();
276   assert(size > 0);
277
278   if (xmalloc_fail_after == 0)
279     {
280       xmalloc_fail_after = -2;
281 #if 0
282       printf("xcalloc: forced failure %s:%d: %s\n", file, line, func);
283 #endif
284       return NULL;
285     }
286   else if (xmalloc_fail_after == -2)
287     {
288       printf("xcalloc: called after failure from %s:%d: %s\n",
289              file, line, func);
290       assert(0);
291     }
292   else if (xmalloc_fail_after > 0)
293     xmalloc_fail_after--;
294
295   ptr = calloc(nmemb, size);
296   if (ptr != NULL)
297     hash_table_add(xmalloc_table, ptr, (int)(nmemb * size), file, line, func);
298   return ptr;
299 }
300
301 void
302 xfree_impl(void *ptr, const char *file, int line, const char *func)
303 {
304   /*LINTED*/(void)&file;
305   /*LINTED*/(void)&line;
306   /*LINTED*/(void)&func;
307   xmalloc_init();
308
309   if (ptr != NULL)
310     hash_table_del(xmalloc_table, ptr);
311   free(ptr);
312 }
313
314 void *
315 xrealloc_impl(void *ptr, size_t new_size, const char *file, int line,
316               const char *func)
317 {
318   void *new_ptr;
319
320   xmalloc_init();
321   assert(ptr != NULL);
322   assert(new_size > 0);
323
324   if (xmalloc_fail_after == 0)
325     {
326       xmalloc_fail_after = -2;
327       return NULL;
328     }
329   else if (xmalloc_fail_after == -2)
330     {
331       printf("xrealloc: called after failure from %s:%d: %s\n",
332              file, line, func);
333       assert(0);
334     }
335   else if (xmalloc_fail_after > 0)
336     xmalloc_fail_after--;
337
338   new_ptr = realloc(ptr, new_size);
339   if (new_ptr != NULL)
340     {
341       hash_table_del(xmalloc_table, ptr);
342       hash_table_add(xmalloc_table, new_ptr, (int)new_size, file, line, func);
343     }
344   return new_ptr;
345 }
346
347
348
349 /* EOF */