5c4d76d34db2a9d44bf4479cef3ed613fc31c04c
[ircu2.10.12-pk.git] / ircd / runmalloc.c
1 /*
2  * Run's malloc/realloc/calloc/free DEBUG tools v2.0
3  *
4  * (c) Copyright 1996, 1997
5  *
6  * Author:
7  *
8  * 1024/624ACAD5 1997/01/26 Carlo Wood, Run on IRC <carlo@runaway.xs4all.nl>
9  * Key fingerprint = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
10  * Get key from pgp-public-keys server or
11  * finger carlo@runaway.xs4all.nl for public key (dialin, try at 21-22h GMT).
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  *
27  * $Id$
28  */
29 #include "runmalloc.h"
30 #include "client.h"
31 #include "ircd.h"
32 #include "numeric.h"
33 #include "numnicks.h"
34 #include "s_debug.h"
35 #include "send.h"
36 #include "struct.h"
37 #include "sys.h"
38
39 #include <assert.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #if defined(DEBUGMALLOC)
44
45 #define MALLOC_HASHTABLE_SIZE 16384
46 #define MallocHash(x) \
47     ((unsigned int)(((((long int)(x) >> 4) * 0xDEECE66D) >> 16) & (long int)0x3fff))
48 #define MAGIC_PREFIX 0xe4c483a1
49 #define MAGIC_POSTFIX 0x435bd0fa
50
51 #ifdef MEMLEAKSTATS
52 typedef struct {
53   const char *filename;
54   int line;
55   int number_of_allocations;
56 #ifdef MEMSIZESTATS
57   size_t size;
58 #endif
59 } location_st;
60
61 #define LOCSIZE 1024            /* Maximum of 256 different locations */
62 static location_st location[LOCSIZE];
63 static unsigned int locations;  /* Counter */
64
65 static unsigned int find_location(const char *filename, int line)
66 {
67   unsigned int hash;
68   hash = line & 0xff;
69   while (location[hash].filename && (location[hash].line != line ||
70       location[hash].filename != filename))
71     if (++hash == LOCSIZE)
72       hash = 0;
73   if (!location[hash].filename)
74   {
75     /* New location */
76     ++locations;
77     location[hash].filename = filename;
78     location[hash].line = line;
79   }
80   return hash;
81 }
82 #endif /* MEMLEAKSTATS */
83
84 #ifdef MEMMAGICNUMS
85 /* The size of this struct should be a multiple of 4 bytes, just in case... */
86 typedef struct {
87   unsigned int prefix_magicnumber;
88 } prefix_blk_st;
89
90 typedef struct {
91   unsigned int postfix_magicnumber;
92 } postfix_blk_st;
93
94 #define SIZEOF_POSTFIX sizeof(postfix_blk_st)
95 #define SIZEOF_PREFIX sizeof(prefix_blk_st)
96 #define HAS_POSTFIX
97
98 #else /* !MEMMAGICNUMS */
99 typedef void prefix_blk_st;
100 #define SIZEOF_PREFIX 0
101 #define SIZEOF_POSTFIX 0
102 #endif /* MEMMAGICNUMS */
103
104 typedef struct hash_entry_st {
105   struct hash_entry_st *next;
106   prefix_blk_st *ptr;
107 #ifdef MEMSIZESTATS
108   size_t size;
109 #endif
110 #ifdef MEMLEAKSTATS
111   unsigned int location;
112 #ifdef MEMTIMESTATS
113   time_t when;
114 #endif /* MEMTIMESTATS */
115 #endif /* MEMLEAKSTATS */
116 } hash_entry_st;
117
118 #define memblkp(prefix_ptr) \
119     ((void *)((size_t)prefix_ptr + SIZEOF_PREFIX))
120 #define prefixp(memblk_ptr) \
121     ((prefix_blk_st *)((size_t)memblk_ptr - SIZEOF_PREFIX))
122 #define postfixp(memblk_ptr, size) \
123     ((postfix_blk_st *)((size_t)memblk_ptr + size))
124
125 static hash_entry_st *hashtable[MALLOC_HASHTABLE_SIZE];
126 #ifdef MEMSIZESTATS
127 static size_t mem_size = 0;     /* Number of allocated bytes  */
128 static unsigned int alloc_cnt = 0;      /* Number of allocated blocks */
129 #endif
130
131 #ifdef MEMLEAKSTATS
132 void report_memleak_stats(struct Client *sptr, int parc, char *parv[])
133 {
134   unsigned int hash;
135   location_st *loc = location;
136
137 #ifdef MEMTIMESTATS
138   time_t till = CurrentTime;
139   time_t from = me.since;
140   if (parc > 3)
141   {
142     location_st tmp_loc[LOCSIZE];
143     hash_entry_st **start;
144     memset(tmp_loc, 0, sizeof(tmp_loc));
145     if (parc > 3)
146       till -= atoi(parv[3]);
147     if (parc > 4)
148       from += atoi(parv[4]);
149     for (start = &hashtable[0];
150         start < &hashtable[MALLOC_HASHTABLE_SIZE]; ++start)
151     {
152       hash_entry_st *hash_entry;
153       for (hash_entry = *start; hash_entry; hash_entry = hash_entry->next)
154         if (hash_entry->when >= from && hash_entry->when <= till)
155         {
156 #ifdef MEMSIZESTATS
157           tmp_loc[hash_entry->location].size += hash_entry->size;
158 #endif
159           tmp_loc[hash_entry->location].number_of_allocations++;
160         }
161     }
162     loc = tmp_loc;
163     if (MyUser(sptr) || Protocol(sptr->from) < 10)
164       sendto_one(sptr, ":%s NOTICE %s :Memory allocated between " TIME_T_FMT
165           " (server start + %s s) and " TIME_T_FMT " (CurrentTime - %s s):",
166           me.name, parv[0], from, parc > 4 ? parv[4] : "0", till,
167           parc > 3 ? parv[3] : "0");
168     else
169       sendto_one(sptr, "%s NOTICE %s%s :Memory allocated between " TIME_T_FMT
170           " (server start + %s s) and " TIME_T_FMT " (CurrentTime - %s s):",
171           NumServ(&me), NumNick(sptr), from, parc > 4 ? parv[4] : "0", till,
172           parc > 3 ? parv[3] : "0");
173   }
174 #endif /* MEMTIMESTATS */
175   for (hash = 0; hash < LOCSIZE; ++hash)
176     if (loc[hash].number_of_allocations > 0)
177       sendto_one(sptr, rpl_str(RPL_STATMEM), me.name, parv[0],
178           loc[hash].number_of_allocations,
179           location[hash].line, location[hash].filename
180 #ifdef MEMSIZESTATS
181           , loc[hash].size
182 #endif
183           );
184 }
185
186 void *RunMalloc_memleak(size_t size, int line, const char *filename)
187 #else   /* !MEMLEAKSTATS */
188 void *MyMalloc(size_t size)
189 #endif  /* MEMLEAKSTATS */
190 {
191   prefix_blk_st *ptr;
192   hash_entry_st *hash_entry;
193   hash_entry_st **hashtablep;
194
195 #ifdef HAS_POSTFIX
196   size += 3;
197   size &= ~3;
198 #endif
199
200   if (!((ptr = (prefix_blk_st *)
201       malloc(SIZEOF_PREFIX + size + SIZEOF_POSTFIX)) &&
202       (hash_entry = (hash_entry_st *) malloc(sizeof(hash_entry_st)))))
203   {
204     if (ptr)
205       free(ptr);
206     (*noMemHandler)();
207     return 0;
208   }
209
210   hashtablep = &hashtable[MallocHash(ptr)];
211   hash_entry->next = *hashtablep;
212   *hashtablep = hash_entry;
213   hash_entry->ptr = ptr;
214 #ifdef MEMLEAKSTATS
215 #ifdef MEMTIMESTATS
216   hash_entry->when = CurrentTime;
217 #endif
218   location[(hash_entry->location =
219       find_location(filename, line))].number_of_allocations++;
220 #endif /* MEMLEAKSTATS */
221 #ifdef MEMSIZESTATS
222   hash_entry->size = size;
223 #ifdef MEMLEAKSTATS
224   location[hash_entry->location].size += size;
225 #endif
226   mem_size += size;
227   ++alloc_cnt;
228 #endif /* MEMSIZESTATS */
229 #ifdef MEMMAGICNUMS
230   ptr->prefix_magicnumber = MAGIC_PREFIX;
231   postfixp(memblkp(ptr), size)->postfix_magicnumber = MAGIC_POSTFIX;
232 #endif
233
234   Debug((DEBUG_MALLOC, "MyMalloc(%u) = %p", size, memblkp(ptr)));
235
236   return memblkp(ptr);
237 }
238
239 #ifdef MEMLEAKSTATS
240 void *RunCalloc_memleak(size_t nmemb, size_t size,
241     int line, const char *filename)
242 #else
243 void *MyCalloc(size_t nmemb, size_t size)
244 #endif /* MEMLEAKSTATS */
245 {
246   void *ptr;
247   size *= nmemb;
248 #ifdef MEMLEAKSTATS
249   if ((ptr = RunMalloc_memleak(size, line, filename)))
250 #else
251   if ((ptr = MyMalloc(size)))
252 #endif /* MEMLEAKSTATS */
253     memset(ptr, 0, size);
254   return ptr;
255 }
256
257 int MyFree_test(void *memblk_ptr)
258 {
259   prefix_blk_st* prefix_ptr = prefixp(memblk_ptr);
260   hash_entry_st* hash_entry;
261   for (hash_entry = hashtable[MallocHash(prefix_ptr)];
262       hash_entry && hash_entry->ptr != prefix_ptr;
263       hash_entry = hash_entry->next);
264   return hash_entry ? 1 : 0;
265 }
266
267 void MyFree(void* memblk_ptr)
268 {
269   prefix_blk_st* prefix_ptr = prefixp(memblk_ptr);
270   hash_entry_st* hash_entry;
271   hash_entry_st* prev_hash_entry = NULL;
272   unsigned int hash = MallocHash(prefix_ptr);
273
274   Debug((DEBUG_MALLOC, "MyFree(%p)", memblk_ptr));
275
276   if (!memblk_ptr)
277     return;
278
279   for (hash_entry = hashtable[hash];
280       hash_entry && hash_entry->ptr != prefix_ptr;
281       prev_hash_entry = hash_entry, hash_entry = hash_entry->next);
282   if (!hash_entry)
283   {
284     Debug((DEBUG_FATAL, "FREEING NON MALLOC PTR !!!"));
285     assert(0 != hash_entry);
286   }
287 #ifdef MEMMAGICNUMS
288   if (prefix_ptr->prefix_magicnumber != MAGIC_PREFIX)
289   {
290     Debug((DEBUG_FATAL, "MAGIC_PREFIX CORRUPT !"));
291     assert(MAGIC_PREFIX == prefix_ptr->prefix_magicnumber);
292   }
293   prefix_ptr->prefix_magicnumber = 12345678;
294   if (postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber
295       != MAGIC_POSTFIX)
296   {
297     Debug((DEBUG_FATAL, "MAGIC_POSTFIX CORRUPT !"));
298     assert(MAGIC_POSTFIX == 
299            postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber);
300   }
301   postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber = 87654321;
302 #endif /* MEMMAGICNUMS */
303
304   if (prev_hash_entry)
305     prev_hash_entry->next = hash_entry->next;
306   else
307     hashtable[hash] = hash_entry->next;
308
309 #ifdef MEMLEAKSTATS
310   location[hash_entry->location].number_of_allocations--;
311 #endif
312
313 #ifdef MEMSIZESTATS
314   mem_size -= hash_entry->size;
315   --alloc_cnt;
316 #ifdef MEMLEAKSTATS
317   location[hash_entry->location].size -= hash_entry->size;
318 #endif
319 #ifdef DEBUGMODE
320   /* Put 0xfefefefe.. in freed memory */
321   memset(prefix_ptr, 0xfe, hash_entry->size + SIZEOF_PREFIX);
322 #endif /* DEBUGMODE */
323 #endif /* MEMSIZESTATS */
324
325   free(hash_entry);
326   free(prefix_ptr);
327 }
328
329 #ifdef MEMLEAKSTATS
330 void *RunRealloc_memleak(void *memblk_ptr, size_t size,
331     int line, const char *filename)
332 #else
333 void *MyRealloc(void *memblk_ptr, size_t size)
334 #endif /* MEMLEAKSTATS */
335 {
336   prefix_blk_st *ptr;
337   prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
338   hash_entry_st *hash_entry, *prev_hash_entry = NULL;
339   hash_entry_st **hashtablep;
340   unsigned int hash;
341
342   if (!memblk_ptr)
343 #ifdef MEMLEAKSTATS
344     return RunMalloc_memleak(size, line, filename);
345 #else
346     return MyMalloc(size);
347 #endif /* MEMLEAKSTATS */
348   if (!size)
349   {
350     MyFree(memblk_ptr);
351     return NULL;
352   }
353
354   for (hash_entry = hashtable[(hash = MallocHash(prefix_ptr))];
355       hash_entry && hash_entry->ptr != prefix_ptr;
356       prev_hash_entry = hash_entry, hash_entry = hash_entry->next);
357   if (!hash_entry)
358   {
359     Debug((DEBUG_FATAL, "REALLOCATING NON MALLOC PTR !!!"));
360     assert(0 != hash_entry);
361   }
362
363 #ifdef MEMMAGICNUMS
364   if (prefix_ptr->prefix_magicnumber != MAGIC_PREFIX)
365   {
366     Debug((DEBUG_FATAL, "MAGIC_PREFIX CORRUPT !"));
367     assert(MAGIC_PREFIX == prefix_ptr->prefix_magicnumber);
368   }
369   if (postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber
370       != MAGIC_POSTFIX)
371   {
372     Debug((DEBUG_FATAL, "MAGIC_POSTFIX CORRUPT !"));
373     assert(MAGIC_POSTFIX ==
374            postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber);
375   }
376 #endif /* MEMMAGICNUMS */
377
378 #ifdef HAS_POSTFIX
379   size += 3;
380   size &= ~3;
381 #endif
382
383 #ifdef MEMMAGICNUMS
384   postfixp(memblkp(prefix_ptr), hash_entry->size)->postfix_magicnumber = 123456;
385 #endif
386 #ifdef MEMLEAKSTATS
387   location[hash_entry->location].number_of_allocations--;
388 #ifdef MEMSIZESTATS
389   location[hash_entry->location].size -= hash_entry->size;
390 #endif /* MEMSIZESTATS */
391 #endif /* MEMLEAKSTATS */
392
393   if (!(ptr =
394       (prefix_blk_st *) realloc(prefix_ptr,
395       SIZEOF_PREFIX + size + SIZEOF_POSTFIX)))
396   {
397     (*noMemHandler)();
398     return 0;
399   }
400
401   if (prev_hash_entry)
402     prev_hash_entry->next = hash_entry->next;
403   else
404     hashtable[hash] = hash_entry->next;
405
406   hashtablep = &hashtable[MallocHash(ptr)];
407   hash_entry->next = *hashtablep;
408   *hashtablep = hash_entry;
409   hash_entry->ptr = ptr;
410 #ifdef MEMLEAKSTATS
411 #ifdef MEMTIMESTATS
412   hash_entry->when = CurrentTime;
413 #endif
414   location[(hash_entry->location =
415       find_location(filename, line))].number_of_allocations++;
416 #endif /* MEMLEAKSTATS */
417 #ifdef MEMSIZESTATS
418   mem_size += size - hash_entry->size;
419   hash_entry->size = size;
420 #ifdef MEMLEAKSTATS
421   location[hash_entry->location].size += size;
422 #endif
423 #endif /* MEMSIZESTATS */
424 #ifdef MEMMAGICNUMS
425   postfixp(memblkp(ptr), size)->postfix_magicnumber = MAGIC_POSTFIX;
426 #endif
427
428   Debug((DEBUG_MALLOC, ": MyRealloc(%p, %u) = %p",
429       memblk_ptr, size, memblkp(ptr)));
430
431   return memblkp(ptr);
432 }
433
434 #ifdef MEMSIZESTATS
435 unsigned int get_alloc_cnt(void)
436 {
437   return alloc_cnt;
438 }
439
440 size_t get_mem_size(void)
441 {
442   return mem_size;
443 }
444 #endif /* MEMSIZESTATS */
445
446 #endif /* !defined(DEBUGMALLOC) */