3 #include "ircd_alloc.h"
9 /* #include <assert.h> -- Now using assert in ircd_log.h */
13 /* To use this you need to get gc6.0 from:
14 * http://www.hpl.hp.com/personal/Hans_Boehm/gc/
15 * and you need to apply the patch in
16 * doc/debug_memleak_gc.patch to your gc6.0 tree, and reconfigure your ircd using
17 --with-leak-detect=path-to-gc6.0/.lib/
18 * You should only do this for debugging builds as it can slow things down
22 #include "ircd_string.h"
24 void *GC_malloc(size_t size);
25 void GC_free(void *ptr);
26 void GC_set_leak_handler(void (*)(void*, int));
27 void GC_gcollect(void);
28 extern int GC_find_leak;
30 /** Header block to track an allocated block's information. */
41 /** Overwrite \a len byte at \a p with 0xDEADBEEF.
42 * @param[out] p Memory buffer to overwrite.
43 * @param[in] len Number of bytes to overwrite.
46 memfrob(void *p, size_t len)
50 const char *pat = "\xde\xad\xbe\xef";
53 for (s = (char*)p, se = s + (len & ~3) - 4;
56 *(uint32_t*)s = *(uint32_t*)pat;
57 for (se = s; se < s; s++)
61 /** Total number of bytes allocated. */
62 static size_t mdbg_bytes_allocated = 0;
63 /** Total number of blocks allocated. */
64 static size_t mdbg_blocks_allocated = 0;
65 /** Last Unix time that we ran garbage collection. */
66 static time_t last_gcollect = 0;
67 /** Minimum interval for garbage collection. */
70 /** Check whether we should run garbage collection.
74 dbg_check_gcollect(void)
76 if (CurrentTime - last_gcollect < GC_FREQ)
79 last_gcollect = CurrentTime;
82 /** Allocate a block of memory.
83 * @param[in] size Number of bytes needed.
84 * @param[in] type Memory operation for block.
85 * @param[in] file File name of allocating function.
86 * @param[in] line Line number of allocating function.
87 * @return Pointer to the newly allocated block.
90 dbg_malloc(size_t size, const char *type, const char *file, int line)
92 struct MemHeader *mh = GC_malloc(size + sizeof(*mh));
95 memfrob((void*)(mh + 1), size);
96 mh->magic = 0xA110CA7E;
97 ircd_strncpy(mh->type, type, sizeof(mh->type) - 1)[sizeof(mh->type) - 1] = 0;
98 ircd_strncpy(mh->file, file, sizeof(mh->file) - 1)[sizeof(mh->file) - 1] = 0;
101 mh->since = CurrentTime;
102 mdbg_bytes_allocated += size;
103 mdbg_blocks_allocated++;
104 dbg_check_gcollect();
105 return (void*)(mh + 1);
108 /** Allocate a zero-initialized block of memory.
109 * @param[in] size Number of bytes needed.
110 * @param[in] type Memory operation for block.
111 * @param[in] file File name of allocating function.
112 * @param[in] line Line number of allocating function.
113 * @return Pointer to the newly allocated block.
116 dbg_malloc_zero(size_t size, const char *type, const char *file, int line)
118 struct MemHeader *mh = GC_malloc(size + sizeof(*mh));
121 memset((void*)(mh + 1), 0, size);
122 mh->magic = 0xA110CA7E;
123 ircd_strncpy(mh->type, type, sizeof(mh->type) - 1)[sizeof(mh->type) - 1] = 0;
124 ircd_strncpy(mh->file, file, sizeof(mh->file) - 1)[sizeof(mh->file) - 1] = 0;
127 mdbg_bytes_allocated += size;
128 mdbg_blocks_allocated++;
129 dbg_check_gcollect();
130 return (void*)(mh + 1);
133 /** Extend an allocated block of memory.
134 * @param[in] ptr Pointer to currently allocated block of memory (may be NULL).
135 * @param[in] size Minimum number of bytes for new block.
136 * @param[in] file File name of allocating function.
137 * @param[in] line Line number of allocating function.
138 * @return Pointer to the extended block of memory.
141 dbg_realloc(void *ptr, size_t size, const char *file, int line)
143 struct MemHeader *mh, *mh2;
145 return dbg_malloc(size, "realloc", file, line);
146 mh = (struct MemHeader*)ptr - 1;
147 assert(mh->magic == 0xA110CA7E);
148 if (mh->length >= size)
150 mh2 = dbg_malloc(size, "realloc", file, line);
153 dbg_free(mh+1, file, line);
156 memcpy(mh2+1, mh+1, mh->length);
157 dbg_free(mh+1, file, line);
158 return (void*)(mh2+1);
161 /** Deallocate a block of memory.
162 * @param[in] ptr Pointer to currently allocated block of memory (may be NULL).
163 * @param[in] file File name of deallocating function.
164 * @param[in] line Line number of deallocating function.
167 dbg_free(void *ptr, const char *file, int line)
169 struct MemHeader *mh = (struct MemHeader*)ptr - 1;
170 /* XXX but bison gives us NULLs */
173 assert(mh->magic == 0xA110CA7E);
174 /* XXX can we get boehmgc to check for references to it? */
175 memfrob(mh, mh->length + sizeof(*mh));
176 mdbg_bytes_allocated -= mh->length;
177 mdbg_blocks_allocated--;
179 dbg_check_gcollect();
182 /** Report number of bytes currently allocated.
183 * @return Number of bytes allocated.
186 fda_get_byte_count(void)
188 dbg_check_gcollect();
189 return mdbg_bytes_allocated;
192 /** Report number of blocks currently allocated.
193 * @return Number of blocks allocated.
196 fda_get_block_count(void)
198 return mdbg_blocks_allocated;
203 /** Callback for when the garbage collector detects a memory leak.
204 * @param[in] p Pointer to leaked memory.
205 * @param[in] sz Length of the block.
208 dbg_memory_leaked(void *p, int sz)
210 struct MemHeader *mh;
211 /* We have to return because the gc "leaks". */
213 if (mh->magic != 0xA110CA7E)
215 sendto_opmask_butone(NULL, SNO_OLDSNO,
216 "%s leak at %s:%u(%u bytes for %u seconds)",
217 mh->type, mh->file, mh->line, mh->length,
218 CurrentTime - mh->since);
220 "%s leak at %s:%u(%u bytes for %u seconds)",
221 mh->type, mh->file, mh->line, mh->length,
222 CurrentTime - mh->since));
225 /** Initialize the memory debugging subsystem. */
227 mem_dbg_initialise(void)
230 GC_set_leak_handler(dbg_memory_leaked);