]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/memdebug.c
3 #include "ircd_alloc.h"
11 /* #include <assert.h> -- Now using assert in ircd_log.h */
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
24 #include "ircd_string.h"
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
;
32 /** Header block to track an allocated block's information. */
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.
48 memfrob(void *p
, size_t len
)
52 const char *pat
= "\xde\xad\xbe\xef";
55 for (s
= (char*)p
, se
= s
+ (len
& ~3) - 4;
58 *(uint32_t*)s
= *(uint32_t*)pat
;
59 for (se
= s
; se
< s
; s
++)
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. */
72 /** Check whether we should run garbage collection.
76 dbg_check_gcollect(void)
78 if (CurrentTime
- last_gcollect
< GC_FREQ
)
81 last_gcollect
= CurrentTime
;
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.
92 dbg_malloc(size_t size
, const char *type
, const char *file
, int line
)
94 struct MemHeader
*mh
= GC_malloc(size
+ sizeof(*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;
103 mh
->since
= CurrentTime
;
104 mdbg_bytes_allocated
+= size
;
105 mdbg_blocks_allocated
++;
106 dbg_check_gcollect();
107 return (void*)(mh
+ 1);
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.
118 dbg_malloc_zero(size_t size
, const char *type
, const char *file
, int line
)
120 struct MemHeader
*mh
= GC_malloc(size
+ sizeof(*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;
129 mdbg_bytes_allocated
+= size
;
130 mdbg_blocks_allocated
++;
131 dbg_check_gcollect();
132 return (void*)(mh
+ 1);
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.
143 dbg_realloc(void *ptr
, size_t size
, const char *file
, int line
)
145 struct MemHeader
*mh
, *mh2
;
147 return dbg_malloc(size
, "realloc", file
, line
);
148 mh
= (struct MemHeader
*)ptr
- 1;
149 assert(mh
->magic
== 0xA110CA7E);
150 if (mh
->length
>= size
)
152 mh2
= dbg_malloc(size
, "realloc", file
, line
);
155 dbg_free(mh
+1, file
, line
);
158 memcpy(mh2
+1, mh
+1, mh
->length
);
159 dbg_free(mh
+1, file
, line
);
160 return (void*)(mh2
+1);
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.
169 dbg_free(void *ptr
, const char *file
, int line
)
171 struct MemHeader
*mh
= (struct MemHeader
*)ptr
- 1;
172 /* XXX but bison gives us NULLs */
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
--;
181 dbg_check_gcollect();
184 /** Report number of bytes currently allocated.
185 * @return Number of bytes allocated.
188 fda_get_byte_count(void)
190 dbg_check_gcollect();
191 return mdbg_bytes_allocated
;
194 /** Report number of blocks currently allocated.
195 * @return Number of blocks allocated.
198 fda_get_block_count(void)
200 return mdbg_blocks_allocated
;
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.
210 dbg_memory_leaked(void *p
, int sz
)
212 struct MemHeader
*mh
;
213 /* We have to return because the gc "leaks". */
215 if (mh
->magic
!= 0xA110CA7E)
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
);
222 "%s leak at %s:%u(%u bytes for %u seconds)",
223 mh
->type
, mh
->file
, mh
->line
, mh
->length
,
224 CurrentTime
- mh
->since
));
227 /** Initialize the memory debugging subsystem. */
229 mem_dbg_initialise(void)
232 GC_set_leak_handler(dbg_memory_leaked
);