fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[ircu2.10.12-pk.git] / ircd / memdebug.c
1 #include <sys/types.h>
2 #include "ircd.h"
3 #include "ircd_alloc.h"
4 #include "ircd_log.h"
5 #include "client.h"
6 #include "s_debug.h"
7 #include "send.h"
8 #include <stdlib.h>
9 #include <string.h>
10
11 /* #include <assert.h> -- Now using assert in ircd_log.h */
12
13 #ifdef MDEBUG
14
15 /* To use this you need to get gc6.0 from:
16  * http://www.hpl.hp.com/personal/Hans_Boehm/gc/
17  * and you need to apply the patch in
18  * doc/debug_memleak_gc.patch to your gc6.0 tree, and reconfigure your ircd using
19  --with-leak-detect=path-to-gc6.0/.lib/
20  * You should only do this for debugging builds as it can slow things down
21  * a bit.
22  */
23
24 #include "ircd_string.h"
25
26 void *GC_malloc(size_t size);
27 void GC_free(void *ptr);
28 void GC_set_leak_handler(void (*)(void*, int));
29 void GC_gcollect(void);
30 extern int GC_find_leak;
31
32 /** Header block to track an allocated block's information. */
33 struct MemHeader
34 {
35   uint32_t magic;
36   char type[32];
37   char file[32];
38   int line;
39   size_t length;
40   time_t since;
41 };
42
43 /** Overwrite \a len byte at \a p with 0xDEADBEEF.
44  * @param[out] p Memory buffer to overwrite.
45  * @param[in] len Number of bytes to overwrite.
46  */
47 void
48 memfrob(void *p, size_t len)
49 {
50   /* deadbeef */
51   int i = 0;
52   const char *pat = "\xde\xad\xbe\xef";
53   char *s, *se;
54
55   for (s = (char*)p, se = s + (len & ~3) - 4;
56        s <= se;
57        s += 4)
58     *(uint32_t*)s = *(uint32_t*)pat;
59   for (se = s; se < s; s++)
60     *s = pat[i++];
61 }
62
63 /** Total number of bytes allocated. */
64 static size_t mdbg_bytes_allocated = 0;
65 /** Total number of blocks allocated. */
66 static size_t mdbg_blocks_allocated = 0;
67 /** Last Unix time that we ran garbage collection. */
68 static time_t last_gcollect = 0;
69 /** Minimum interval for garbage collection. */
70 #define GC_FREQ 5
71
72 /** Check whether we should run garbage collection.
73  * If so, do it.
74  */
75 void
76 dbg_check_gcollect(void)
77 {
78   if (CurrentTime - last_gcollect < GC_FREQ)
79     return;
80   GC_gcollect();
81   last_gcollect = CurrentTime;
82 }
83
84 /** Allocate a block of memory.
85  * @param[in] size Number of bytes needed.
86  * @param[in] type Memory operation for block.
87  * @param[in] file File name of allocating function.
88  * @param[in] line Line number of allocating function.
89  * @return Pointer to the newly allocated block.
90  */
91 void*
92 dbg_malloc(size_t size, const char *type, const char *file, int line)
93 {
94   struct MemHeader *mh = GC_malloc(size + sizeof(*mh));
95   if (mh == NULL)
96     return mh;
97   memfrob((void*)(mh + 1), size);
98   mh->magic = 0xA110CA7E;
99   ircd_strncpy(mh->type, type, sizeof(mh->type) - 1)[sizeof(mh->type) - 1] = 0;
100   ircd_strncpy(mh->file, file, sizeof(mh->file) - 1)[sizeof(mh->file) - 1] = 0;
101   mh->line = line;
102   mh->length = size;
103   mh->since = CurrentTime;
104   mdbg_bytes_allocated += size;
105   mdbg_blocks_allocated++;
106   dbg_check_gcollect();
107   return (void*)(mh + 1);
108 }
109
110 /** Allocate a zero-initialized block of memory.
111  * @param[in] size Number of bytes needed.
112  * @param[in] type Memory operation for block.
113  * @param[in] file File name of allocating function.
114  * @param[in] line Line number of allocating function.
115  * @return Pointer to the newly allocated block.
116  */
117 void*
118 dbg_malloc_zero(size_t size, const char *type, const char *file, int line)
119 {
120   struct MemHeader *mh = GC_malloc(size + sizeof(*mh));
121   if (mh == NULL)
122     return mh;
123   memset((void*)(mh + 1), 0, size);
124   mh->magic = 0xA110CA7E;
125   ircd_strncpy(mh->type, type, sizeof(mh->type) - 1)[sizeof(mh->type) - 1] = 0;
126   ircd_strncpy(mh->file, file, sizeof(mh->file) - 1)[sizeof(mh->file) - 1] = 0;
127   mh->line = line;
128   mh->length = size;
129   mdbg_bytes_allocated += size;
130   mdbg_blocks_allocated++;
131   dbg_check_gcollect();
132   return (void*)(mh + 1);
133 }
134
135 /** Extend an allocated block of memory.
136  * @param[in] ptr Pointer to currently allocated block of memory (may be NULL).
137  * @param[in] size Minimum number of bytes for new block.
138  * @param[in] file File name of allocating function.
139  * @param[in] line Line number of allocating function.
140  * @return Pointer to the extended block of memory.
141  */
142 void*
143 dbg_realloc(void *ptr, size_t size, const char *file, int line)
144 {
145   struct MemHeader *mh, *mh2;
146   if (ptr == NULL)
147     return dbg_malloc(size, "realloc", file, line);
148   mh = (struct MemHeader*)ptr - 1;
149   assert(mh->magic == 0xA110CA7E);
150   if (mh->length >= size)
151     return mh;
152   mh2 = dbg_malloc(size, "realloc", file, line);
153   if (mh2 == NULL)
154   {
155     dbg_free(mh+1, file, line);
156     return NULL;
157   }
158   memcpy(mh2+1, mh+1, mh->length);
159   dbg_free(mh+1, file, line);
160   return (void*)(mh2+1);
161 }
162
163 /** Deallocate a block of memory.
164  * @param[in] ptr Pointer to currently allocated block of memory (may be NULL).
165  * @param[in] file File name of deallocating function.
166  * @param[in] line Line number of deallocating function.
167  */
168 void
169 dbg_free(void *ptr, const char *file, int line)
170 {
171   struct MemHeader *mh = (struct MemHeader*)ptr - 1;
172   /* XXX but bison gives us NULLs */
173   if (ptr == NULL)
174     return;
175   assert(mh->magic == 0xA110CA7E);
176   /* XXX can we get boehmgc to check for references to it? */
177   memfrob(mh, mh->length + sizeof(*mh));
178   mdbg_bytes_allocated -= mh->length;
179   mdbg_blocks_allocated--;
180   GC_free(mh);
181   dbg_check_gcollect();
182 }
183
184 /** Report number of bytes currently allocated.
185  * @return Number of bytes allocated.
186  */
187 size_t
188 fda_get_byte_count(void)
189 {
190   dbg_check_gcollect();
191   return mdbg_bytes_allocated;
192 }
193
194 /** Report number of blocks currently allocated.
195  * @return Number of blocks allocated.
196  */
197 size_t
198 fda_get_block_count(void)
199 {
200   return mdbg_blocks_allocated;
201 }
202
203 #include <stdio.h>
204
205 /** Callback for when the garbage collector detects a memory leak.
206  * @param[in] p Pointer to leaked memory.
207  * @param[in] sz Length of the block.
208  */
209 void
210 dbg_memory_leaked(void *p, int sz)
211 {
212   struct MemHeader *mh;
213   /* We have to return because the gc "leaks". */
214   mh = p;
215   if (mh->magic != 0xA110CA7E)
216     return;
217   sendto_opmask_butone(NULL, SNO_OLDSNO,
218                        "%s leak at %s:%u(%u bytes for %u seconds)",
219                        mh->type, mh->file, mh->line, mh->length,
220                        CurrentTime - mh->since);
221   Debug((DEBUG_ERROR,
222          "%s leak at %s:%u(%u bytes for %u seconds)",
223          mh->type, mh->file, mh->line, mh->length,
224          CurrentTime - mh->since));
225 }
226
227 /** Initialize the memory debugging subsystem. */
228 void
229 mem_dbg_initialise(void)
230 {
231   GC_find_leak = 1;
232   GC_set_leak_handler(dbg_memory_leaked);
233 }
234
235 #endif