]> jfr.im git - irc/quakenet/snircd.git/blame - ircd/memdebug.c
fixed autochanmodes code so it works for channel modes +CN
[irc/quakenet/snircd.git] / ircd / memdebug.c
CommitLineData
189935b1 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
26void *GC_malloc(size_t size);
27void GC_free(void *ptr);
28void GC_set_leak_handler(void (*)(void*, int));
29void GC_gcollect(void);
30extern int GC_find_leak;
31
32/** Header block to track an allocated block's information. */
33struct 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 */
47void
48memfrob(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. */
64static size_t mdbg_bytes_allocated = 0;
65/** Total number of blocks allocated. */
66static size_t mdbg_blocks_allocated = 0;
67/** Last Unix time that we ran garbage collection. */
68static 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 */
75void
76dbg_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 */
91void*
92dbg_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 */
117void*
118dbg_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 */
142void*
143dbg_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 */
168void
169dbg_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 */
187size_t
188fda_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 */
197size_t
198fda_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 */
209void
210dbg_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. */
228void
229mem_dbg_initialise(void)
230{
231 GC_find_leak = 1;
232 GC_set_leak_handler(dbg_memory_leaked);
233}
234
235#endif