2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Memory Management
23 * \author Mark Spencer <markster@digium.com>
26 #ifdef __AST_DEBUG_MALLOC
30 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include "asterisk/cli.h"
37 #include "asterisk/logger.h"
38 #include "asterisk/options.h"
39 #include "asterisk/lock.h"
40 #include "asterisk/strings.h"
41 #include "asterisk/unaligned.h"
43 #define SOME_PRIME 563
55 /* Undefine all our macros */
65 #define FENCE_MAGIC 0xdeadbeef
69 static struct ast_region
{
70 struct ast_region
*next
;
75 unsigned int cache
; /* region was allocated as part of a cache pool */
78 unsigned char data
[0];
79 } *regions
[SOME_PRIME
];
82 (((unsigned long)(a)) % SOME_PRIME)
84 AST_MUTEX_DEFINE_STATIC_NOTRACKING(reglock
);
86 #define astmm_log(...) \
88 fprintf(stderr, __VA_ARGS__); \
90 fprintf(mmlog, __VA_ARGS__); \
95 static inline void *__ast_alloc_region(size_t size
, const enum func_type which
, const char *file
, int lineno
, const char *func
, unsigned int cache
)
97 struct ast_region
*reg
;
102 if (!(reg
= malloc(size
+ sizeof(*reg
) + sizeof(*fence
)))) {
103 astmm_log("Memory Allocation Failure - '%d' bytes in function %s "
104 "at line %d of %s\n", (int) size
, func
, lineno
, file
);
107 ast_copy_string(reg
->file
, file
, sizeof(reg
->file
));
108 ast_copy_string(reg
->func
, func
, sizeof(reg
->func
));
109 reg
->lineno
= lineno
;
115 reg
->fence
= FENCE_MAGIC
;
116 fence
= (ptr
+ reg
->len
);
117 put_unaligned_uint32(fence
, FENCE_MAGIC
);
119 ast_mutex_lock(®lock
);
120 reg
->next
= regions
[hash
];
122 ast_mutex_unlock(®lock
);
127 static inline size_t __ast_sizeof_region(void *ptr
)
129 int hash
= HASH(ptr
);
130 struct ast_region
*reg
;
133 ast_mutex_lock(®lock
);
134 for (reg
= regions
[hash
]; reg
; reg
= reg
->next
) {
135 if (reg
->data
== ptr
) {
140 ast_mutex_unlock(®lock
);
145 static void __ast_free_region(void *ptr
, const char *file
, int lineno
, const char *func
)
147 int hash
= HASH(ptr
);
148 struct ast_region
*reg
, *prev
= NULL
;
151 ast_mutex_lock(®lock
);
152 for (reg
= regions
[hash
]; reg
; reg
= reg
->next
) {
153 if (reg
->data
== ptr
) {
155 prev
->next
= reg
->next
;
157 regions
[hash
] = reg
->next
;
162 ast_mutex_unlock(®lock
);
165 fence
= (unsigned int *)(reg
->data
+ reg
->len
);
166 if (reg
->fence
!= FENCE_MAGIC
) {
167 astmm_log("WARNING: Low fence violation at %p, in %s of %s, "
168 "line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
170 if (get_unaligned_uint32(fence
) != FENCE_MAGIC
) {
171 astmm_log("WARNING: High fence violation at %p, in %s of %s, "
172 "line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
176 astmm_log("WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",
177 ptr
, func
, file
, lineno
);
181 void *__ast_calloc(size_t nmemb
, size_t size
, const char *file
, int lineno
, const char *func
)
185 if ((ptr
= __ast_alloc_region(size
* nmemb
, FUNC_CALLOC
, file
, lineno
, func
, 0)))
186 memset(ptr
, 0, size
* nmemb
);
191 void *__ast_calloc_cache(size_t nmemb
, size_t size
, const char *file
, int lineno
, const char *func
)
195 if ((ptr
= __ast_alloc_region(size
* nmemb
, FUNC_CALLOC
, file
, lineno
, func
, 1)))
196 memset(ptr
, 0, size
* nmemb
);
201 void *__ast_malloc(size_t size
, const char *file
, int lineno
, const char *func
)
203 return __ast_alloc_region(size
, FUNC_MALLOC
, file
, lineno
, func
, 0);
206 void __ast_free(void *ptr
, const char *file
, int lineno
, const char *func
)
208 __ast_free_region(ptr
, file
, lineno
, func
);
211 void *__ast_realloc(void *ptr
, size_t size
, const char *file
, int lineno
, const char *func
)
216 if (ptr
&& !(len
= __ast_sizeof_region(ptr
))) {
217 astmm_log("WARNING: Realloc of unalloced memory at %p, in %s of %s, "
218 "line %d\n", ptr
, func
, file
, lineno
);
222 if (!(tmp
= __ast_alloc_region(size
, FUNC_REALLOC
, file
, lineno
, func
, 0)))
228 memcpy(tmp
, ptr
, len
);
229 __ast_free_region(ptr
, file
, lineno
, func
);
235 char *__ast_strdup(const char *s
, const char *file
, int lineno
, const char *func
)
244 if ((ptr
= __ast_alloc_region(len
, FUNC_STRDUP
, file
, lineno
, func
, 0)))
250 char *__ast_strndup(const char *s
, size_t n
, const char *file
, int lineno
, const char *func
)
261 if ((ptr
= __ast_alloc_region(len
, FUNC_STRNDUP
, file
, lineno
, func
, 0)))
267 int __ast_asprintf(const char *file
, int lineno
, const char *func
, char **strp
, const char *fmt
, ...)
276 size
= vsnprintf(&s
, 1, fmt
, ap2
);
278 if (!(*strp
= __ast_alloc_region(size
+ 1, FUNC_ASPRINTF
, file
, lineno
, func
, 0))) {
282 vsnprintf(*strp
, size
+ 1, fmt
, ap
);
288 int __ast_vasprintf(char **strp
, const char *fmt
, va_list ap
, const char *file
, int lineno
, const char *func
)
296 size
= vsnprintf(&s
, 1, fmt
, ap2
);
298 if (!(*strp
= __ast_alloc_region(size
+ 1, FUNC_VASPRINTF
, file
, lineno
, func
, 0))) {
302 vsnprintf(*strp
, size
+ 1, fmt
, ap
);
307 static int handle_show_memory(int fd
, int argc
, char *argv
[])
310 struct ast_region
*reg
;
312 unsigned int len
= 0;
313 unsigned int cache_len
= 0;
314 unsigned int count
= 0;
320 ast_mutex_lock(®lock
);
321 for (x
= 0; x
< SOME_PRIME
; x
++) {
322 for (reg
= regions
[x
]; reg
; reg
= reg
->next
) {
323 if (!fn
|| !strcasecmp(fn
, reg
->file
) || !strcasecmp(fn
, "anomolies")) {
324 fence
= (unsigned int *)(reg
->data
+ reg
->len
);
325 if (reg
->fence
!= FENCE_MAGIC
) {
326 astmm_log("WARNING: Low fence violation at %p, "
327 "in %s of %s, line %d\n", reg
->data
,
328 reg
->func
, reg
->file
, reg
->lineno
);
330 if (get_unaligned_uint32(fence
) != FENCE_MAGIC
) {
331 astmm_log("WARNING: High fence violation at %p, in %s of %s, "
332 "line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
335 if (!fn
|| !strcasecmp(fn
, reg
->file
)) {
336 ast_cli(fd
, "%10d bytes allocated%s in %20s at line %5d of %s\n",
337 (int) reg
->len
, reg
->cache
? " (cache)" : "",
338 reg
->func
, reg
->lineno
, reg
->file
);
341 cache_len
+= reg
->len
;
346 ast_mutex_unlock(®lock
);
349 ast_cli(fd
, "%d bytes allocated (%d in caches) in %d allocations\n", len
, cache_len
, count
);
351 ast_cli(fd
, "%d bytes allocated in %d allocations\n", len
, count
);
353 return RESULT_SUCCESS
;
356 static int handle_show_memory_summary(int fd
, int argc
, char *argv
[])
360 struct ast_region
*reg
;
361 unsigned int len
= 0;
362 unsigned int cache_len
= 0;
364 struct file_summary
{
369 struct file_summary
*next
;
370 } *list
= NULL
, *cur
;
375 ast_mutex_lock(®lock
);
376 for (x
= 0; x
< SOME_PRIME
; x
++) {
377 for (reg
= regions
[x
]; reg
; reg
= reg
->next
) {
378 if (fn
&& strcasecmp(fn
, reg
->file
))
381 for (cur
= list
; cur
; cur
= cur
->next
) {
382 if ((!fn
&& !strcmp(cur
->fn
, reg
->file
)) || (fn
&& !strcmp(cur
->fn
, reg
->func
)))
386 cur
= alloca(sizeof(*cur
));
387 memset(cur
, 0, sizeof(*cur
));
388 ast_copy_string(cur
->fn
, fn
? reg
->func
: reg
->file
, sizeof(cur
->fn
));
393 cur
->len
+= reg
->len
;
395 cur
->cache_len
+= reg
->len
;
399 ast_mutex_unlock(®lock
);
401 /* Dump the whole list */
402 for (cur
= list
; cur
; cur
= cur
->next
) {
404 cache_len
+= cur
->cache_len
;
406 if (cur
->cache_len
) {
408 ast_cli(fd
, "%10d bytes (%10d cache) in %d allocations in function '%s' of '%s'\n",
409 cur
->len
, cur
->cache_len
, cur
->count
, cur
->fn
, fn
);
411 ast_cli(fd
, "%10d bytes (%10d cache) in %d allocations in file '%s'\n",
412 cur
->len
, cur
->cache_len
, cur
->count
, cur
->fn
);
416 ast_cli(fd
, "%10d bytes in %d allocations in function '%s' of '%s'\n",
417 cur
->len
, cur
->count
, cur
->fn
, fn
);
419 ast_cli(fd
, "%10d bytes in %d allocations in file '%s'\n",
420 cur
->len
, cur
->count
, cur
->fn
);
426 ast_cli(fd
, "%d bytes allocated (%d in caches) in %d allocations\n", len
, cache_len
, count
);
428 ast_cli(fd
, "%d bytes allocated in %d allocations\n", len
, count
);
430 return RESULT_SUCCESS
;
433 static char show_memory_help
[] =
434 "Usage: memory show allocations [<file>]\n"
435 " Dumps a list of all segments of allocated memory, optionally\n"
436 "limited to those from a specific file\n";
438 static char show_memory_summary_help
[] =
439 "Usage: memory show summary [<file>]\n"
440 " Summarizes heap memory allocations by file, or optionally\n"
441 "by function, if a file is specified\n";
443 static struct ast_cli_entry cli_show_memory_allocations_deprecated
= {
444 { "show", "memory", "allocations", NULL
},
445 handle_show_memory
, NULL
,
448 static struct ast_cli_entry cli_show_memory_summary_deprecated
= {
449 { "show", "memory", "summary", NULL
},
450 handle_show_memory_summary
, NULL
,
453 static struct ast_cli_entry cli_memory
[] = {
454 { { "memory", "show", "allocations", NULL
},
455 handle_show_memory
, "Display outstanding memory allocations",
456 show_memory_help
, NULL
, &cli_show_memory_allocations_deprecated
},
458 { { "memory", "show", "summary", NULL
},
459 handle_show_memory_summary
, "Summarize outstanding memory allocations",
460 show_memory_summary_help
, NULL
, &cli_show_memory_summary_deprecated
},
463 void __ast_mm_init(void)
465 char filename
[PATH_MAX
];
467 ast_cli_register_multiple(cli_memory
, sizeof(cli_memory
) / sizeof(struct ast_cli_entry
));
469 snprintf(filename
, sizeof(filename
), "%s/mmlog", (char *)ast_config_AST_LOG_DIR
);
472 ast_verbose("Asterisk Malloc Debugger Started (see %s))\n", filename
);
474 if ((mmlog
= fopen(filename
, "a+"))) {
475 fprintf(mmlog
, "%ld - New session\n", (long)time(NULL
));