7baf8bcc517f4d553a7839c5fabd2a5d4a7a641f
[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
28 #include "sys.h"
29
30 #ifdef DEBUGMALLOC
31 #include <stdlib.h>
32 #include "h.h"
33
34 RCSTAG_CC("$Id$");
35
36 #define MALLOC_HASHTABLE_SIZE 16384
37 #define MallocHash(x) \
38     ((unsigned int)(((((long int)(x) >> 4) * 0xDEECE66D) >> 16) & (long int)0x3fff))
39 #define MAGIC_PREFIX 0xe4c483a1
40 #define MAGIC_POSTFIX 0x435bd0fa
41
42 #ifdef MEMLEAKSTATS
43 typedef struct {
44   const char *filename;
45   int line;
46   int number_of_allocations;
47 #ifdef MEMSIZESTATS
48   size_t size;
49 #endif
50 } location_st;
51
52 #define LOCSIZE 1024            /* Maximum of 256 different locations */
53 static location_st location[LOCSIZE];
54 static unsigned int locations;  /* Counter */
55
56 static unsigned int find_location(const char *filename, int line)
57 {
58   register unsigned int hash;
59   hash = line & 0xff;
60   while (location[hash].filename && (location[hash].line != line ||
61       location[hash].filename != filename))
62     if (++hash == LOCSIZE)
63       hash = 0;
64   if (!location[hash].filename)
65   {
66     /* New location */
67     ++locations;
68     location[hash].filename = filename;
69     location[hash].line = line;
70   }
71   return hash;
72 }
73 #endif
74
75 #ifdef MEMMAGICNUMS
76 /* The size of this struct should be a multiple of 4 bytes, just in case... */
77 typedef struct {
78 #ifdef MEMMAGICNUMS
79   unsigned int prefix_magicnumber;
80 #endif
81 } prefix_blk_st;
82
83 #define SIZEOF_PREFIX sizeof(prefix_blk_st)
84 #else
85 typedef void prefix_blk_st;
86 #define SIZEOF_PREFIX 0
87 #endif
88
89 #ifdef MEMMAGICNUMS
90 typedef struct {
91   unsigned int postfix_magicnumber;
92 } postfix_blk_st;
93
94 #define SIZEOF_POSTFIX sizeof(postfix_blk_st)
95 #define HAS_POSTFIX
96 #else
97 #define SIZEOF_POSTFIX 0
98 #endif
99
100 typedef struct hash_entry_st {
101   struct hash_entry_st *next;
102   prefix_blk_st *ptr;
103 #ifdef MEMSIZESTATS
104   size_t size;
105 #endif
106 #ifdef MEMLEAKSTATS
107   unsigned int location;
108 #ifdef MEMTIMESTATS
109   time_t when;
110 #endif
111 #endif
112 } hash_entry_st;
113
114 #define memblkp(prefix_ptr) \
115     ((void *)((size_t)prefix_ptr + SIZEOF_PREFIX))
116 #define prefixp(memblk_ptr) \
117     ((prefix_blk_st *)((size_t)memblk_ptr - SIZEOF_PREFIX))
118 #define postfixp(memblk_ptr, size) \
119     ((postfix_blk_st *)((size_t)memblk_ptr + size))
120
121 static hash_entry_st *hashtable[MALLOC_HASHTABLE_SIZE];
122 #ifdef MEMSIZESTATS
123 static size_t mem_size = 0;     /* Number of allocated bytes  */
124 static unsigned int alloc_cnt = 0;      /* Number of allocated blocks */
125 #endif
126
127 #ifdef MEMLEAKSTATS
128 #include "struct.h"
129 #include "send.h"
130 #include "numeric.h"
131 #include "s_err.h"
132 #include "ircd.h"
133 #include "s_serv.h"
134 #include "numnicks.h"
135
136 void report_memleak_stats(aClient *sptr, int parc, char *parv[])
137 {
138   unsigned int hash;
139   location_st *loc = location;
140
141 #ifdef MEMTIMESTATS
142   time_t till = now;
143   time_t from = me.since;
144   if (parc > 3)
145   {
146     location_st tmp_loc[LOCSIZE];
147     hash_entry_st **start;
148     memset(tmp_loc, 0, sizeof(tmp_loc));
149     if (parc > 3)
150       till -= atoi(parv[3]);
151     if (parc > 4)
152       from += atoi(parv[4]);
153     for (start = &hashtable[0];
154         start < &hashtable[MALLOC_HASHTABLE_SIZE]; ++start)
155     {
156       hash_entry_st *hash_entry;
157       for (hash_entry = *start; hash_entry; hash_entry = hash_entry->next)
158         if (hash_entry->when >= from && hash_entry->when <= till)
159         {
160 #ifdef MEMSIZESTATS
161           tmp_loc[hash_entry->location].size += hash_entry->size;
162 #endif
163           tmp_loc[hash_entry->location].number_of_allocations++;
164         }
165     }
166     loc = tmp_loc;
167     if (MyUser(sptr) || Protocol(sptr->from) < 10)
168       sendto_one(sptr, ":%s NOTICE %s :Memory allocated between " TIME_T_FMT
169           " (server start + %s s) and " TIME_T_FMT " (now - %s s):",
170           me.name, parv[0], from, parc > 4 ? parv[4] : "0", till,
171           parc > 3 ? parv[3] : "0");
172     else
173       sendto_one(sptr, "%s NOTICE %s%s :Memory allocated between " TIME_T_FMT
174           " (server start + %s s) and " TIME_T_FMT " (now - %s s):",
175           NumServ(&me), NumNick(sptr), from, parc > 4 ? parv[4] : "0", till,
176           parc > 3 ? parv[3] : "0");
177   }
178 #endif
179   for (hash = 0; hash < LOCSIZE; ++hash)
180     if (loc[hash].number_of_allocations > 0)
181       sendto_one(sptr, rpl_str(RPL_STATMEM), me.name, parv[0],
182           loc[hash].number_of_allocations,
183           location[hash].line, location[hash].filename
184 #ifdef MEMSIZESTATS
185           , loc[hash].size
186 #endif
187           );
188 }
189
190 void *RunMalloc_memleak(size_t size, int line, const char *filename)
191 #else
192 void *RunMalloc(size_t size)
193 #endif
194 {
195   register prefix_blk_st *ptr;
196   register hash_entry_st *hash_entry;
197   register hash_entry_st **hashtablep;
198
199 #ifdef HAS_POSTFIX
200   size += 3;
201   size &= ~3;
202 #endif
203
204   if (!((ptr = (prefix_blk_st *)
205       malloc(SIZEOF_PREFIX + size + SIZEOF_POSTFIX)) &&
206       (hash_entry = (hash_entry_st *) malloc(sizeof(hash_entry_st)))))
207   {
208     if (ptr)
209       free(ptr);
210     Debug((DEBUG_FATAL, "Out of memory !"));
211     return NULL;
212   }
213
214   hashtablep = &hashtable[MallocHash(ptr)];
215   hash_entry->next = *hashtablep;
216   *hashtablep = hash_entry;
217   hash_entry->ptr = ptr;
218 #ifdef MEMLEAKSTATS
219 #ifdef MEMTIMESTATS
220   hash_entry->when = now;
221 #endif
222   location[(hash_entry->location =
223       find_location(filename, line))].number_of_allocations++;
224 #endif
225 #ifdef MEMSIZESTATS
226   hash_entry->size = size;
227 #ifdef MEMLEAKSTATS
228   location[hash_entry->location].size += size;
229 #endif
230   mem_size += size;
231   ++alloc_cnt;
232 #endif
233 #ifdef MEMMAGICNUMS
234   ptr->prefix_magicnumber = MAGIC_PREFIX;
235   postfixp(memblkp(ptr), size)->postfix_magicnumber = MAGIC_POSTFIX;
236 #endif
237
238   Debug((DEBUG_DEBUG, "RunMalloc(%u) = %p", size, memblkp(ptr)));
239
240   return memblkp(ptr);
241 }
242
243 #ifdef MEMLEAKSTATS
244 void *RunCalloc_memleak(size_t nmemb, size_t size,
245     int line, const char *filename)
246 #else
247 void *RunCalloc(size_t nmemb, size_t size)
248 #endif
249 {
250   void *ptr;
251   size *= nmemb;
252 #ifdef MEMLEAKSTATS
253   if ((ptr = RunMalloc_memleak(size, line, filename)))
254 #else
255   if ((ptr = RunMalloc(size)))
256 #endif
257     memset(ptr, 0, size);
258   return ptr;
259 }
260
261 int RunFree_test(void *memblk_ptr)
262 {
263   register prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
264   register hash_entry_st *hash_entry;
265   for (hash_entry = hashtable[MallocHash(prefix_ptr)];
266       hash_entry && hash_entry->ptr != prefix_ptr;
267       hash_entry = hash_entry->next);
268   return hash_entry ? 1 : 0;
269 }
270
271 void RunFree(void *memblk_ptr)
272 {
273   register prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
274   register hash_entry_st *hash_entry, *prev_hash_entry = NULL;
275   unsigned int hash = MallocHash(prefix_ptr);
276
277   Debug((DEBUG_DEBUG, "RunFree(%p)", memblk_ptr));
278
279   if (!memblk_ptr)
280     return;
281
282   for (hash_entry = hashtable[hash];
283       hash_entry && hash_entry->ptr != prefix_ptr;
284       prev_hash_entry = hash_entry, hash_entry = hash_entry->next);
285   if (!hash_entry)
286   {
287     Debug((DEBUG_FATAL, "FREEING NON MALLOC PTR !!!"));
288     MyCoreDump;
289   }
290 #ifdef MEMMAGICNUMS
291   if (prefix_ptr->prefix_magicnumber != MAGIC_PREFIX)
292   {
293     Debug((DEBUG_FATAL, "MAGIC_PREFIX CORRUPT !"));
294     MyCoreDump;
295   }
296   prefix_ptr->prefix_magicnumber = 12345678;
297   if (postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber
298       != MAGIC_POSTFIX)
299   {
300     Debug((DEBUG_FATAL, "MAGIC_POSTFIX CORRUPT !"));
301     MyCoreDump;
302   }
303   postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber = 87654321;
304 #endif
305
306   if (prev_hash_entry)
307     prev_hash_entry->next = hash_entry->next;
308   else
309     hashtable[hash] = hash_entry->next;
310
311 #ifdef MEMLEAKSTATS
312   location[hash_entry->location].number_of_allocations--;
313 #endif
314
315 #ifdef MEMSIZESTATS
316   mem_size -= hash_entry->size;
317   --alloc_cnt;
318 #ifdef MEMLEAKSTATS
319   location[hash_entry->location].size -= hash_entry->size;
320 #endif
321 #ifdef DEBUGMODE
322   /* Put 0xfefefefe.. in freed memory */
323 #ifndef memset
324   memset(prefix_ptr, 0xfe, hash_entry->size + SIZEOF_PREFIX);
325 #else
326   {
327     register char *p = prefix_ptr;
328     size_t len = hash_entry->size + SIZEOF_PREFIX;
329     for (; len; --len)
330       *p++ = 0xfe;
331   }
332 #endif
333 #endif
334 #endif
335
336   free(hash_entry);
337   free(prefix_ptr);
338 }
339
340 #ifdef MEMLEAKSTATS
341 void *RunRealloc_memleak(void *memblk_ptr, size_t size,
342     int line, const char *filename)
343 #else
344 void *RunRealloc(void *memblk_ptr, size_t size)
345 #endif
346 {
347   register prefix_blk_st *ptr;
348   register prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
349   register hash_entry_st *hash_entry, *prev_hash_entry = NULL;
350   register hash_entry_st **hashtablep;
351   unsigned int hash;
352
353   if (!memblk_ptr)
354 #ifdef MEMLEAKSTATS
355     return RunMalloc_memleak(size, line, filename);
356 #else
357     return RunMalloc(size);
358 #endif
359   if (!size)
360   {
361     RunFree(memblk_ptr);
362     return NULL;
363   }
364
365   for (hash_entry = hashtable[(hash = MallocHash(prefix_ptr))];
366       hash_entry && hash_entry->ptr != prefix_ptr;
367       prev_hash_entry = hash_entry, hash_entry = hash_entry->next);
368   if (!hash_entry)
369   {
370     Debug((DEBUG_FATAL, "REALLOCATING NON MALLOC PTR !!!"));
371     MyCoreDump;
372   }
373
374 #ifdef MEMMAGICNUMS
375   if (prefix_ptr->prefix_magicnumber != MAGIC_PREFIX)
376   {
377     Debug((DEBUG_FATAL, "MAGIC_PREFIX CORRUPT !"));
378     MyCoreDump;
379   }
380   if (postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber
381       != MAGIC_POSTFIX)
382   {
383     Debug((DEBUG_FATAL, "MAGIC_POSTFIX CORRUPT !"));
384     MyCoreDump;
385   }
386 #endif
387
388 #ifdef HAS_POSTFIX
389   size += 3;
390   size &= ~3;
391 #endif
392
393 #ifdef MEMMAGICNUMS
394   postfixp(memblkp(prefix_ptr), hash_entry->size)->postfix_magicnumber = 123456;
395 #endif
396 #ifdef MEMLEAKSTATS
397   location[hash_entry->location].number_of_allocations--;
398 #ifdef MEMSIZESTATS
399   location[hash_entry->location].size -= hash_entry->size;
400 #endif
401 #endif
402
403   if (!(ptr =
404       (prefix_blk_st *) realloc(prefix_ptr,
405       SIZEOF_PREFIX + size + SIZEOF_POSTFIX)))
406   {
407     Debug((DEBUG_FATAL, "RunRealloc: Out of memory :"));
408     return NULL;
409   }
410
411   if (prev_hash_entry)
412     prev_hash_entry->next = hash_entry->next;
413   else
414     hashtable[hash] = hash_entry->next;
415
416   hashtablep = &hashtable[MallocHash(ptr)];
417   hash_entry->next = *hashtablep;
418   *hashtablep = hash_entry;
419   hash_entry->ptr = ptr;
420 #ifdef MEMLEAKSTATS
421 #ifdef MEMTIMESTATS
422   hash_entry->when = now;
423 #endif
424   location[(hash_entry->location =
425       find_location(filename, line))].number_of_allocations++;
426 #endif
427 #ifdef MEMSIZESTATS
428   mem_size += size - hash_entry->size;
429   hash_entry->size = size;
430 #ifdef MEMLEAKSTATS
431   location[hash_entry->location].size += size;
432 #endif
433 #endif
434 #ifdef MEMMAGICNUMS
435   postfixp(memblkp(ptr), size)->postfix_magicnumber = MAGIC_POSTFIX;
436 #endif
437
438   Debug((DEBUG_DEBUG, ": RunRealloc(%p, %u) = %p",
439       memblk_ptr, size, memblkp(ptr)));
440
441   return memblkp(ptr);
442 }
443
444 #ifdef MEMSIZESTATS
445 unsigned int get_alloc_cnt(void)
446 {
447   return alloc_cnt;
448 }
449
450 size_t get_mem_size(void)
451 {
452   return mem_size;
453 }
454 #endif
455
456 #endif /* DEBUGMALLOC */