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
;
77 unsigned char data
[0];
78 } *regions
[SOME_PRIME
];
81 (((unsigned long)(a)) % SOME_PRIME)
83 AST_MUTEX_DEFINE_STATIC(reglock
);
84 AST_MUTEX_DEFINE_STATIC(showmemorylock
);
86 static inline void *__ast_alloc_region(size_t size
, const enum func_type which
, const char *file
, int lineno
, const char *func
)
88 struct ast_region
*reg
;
92 reg
= malloc(size
+ sizeof(*reg
) + sizeof(*fence
));
93 ast_mutex_lock(®lock
);
95 ast_copy_string(reg
->file
, file
, sizeof(reg
->file
));
96 reg
->file
[sizeof(reg
->file
) - 1] = '\0';
97 ast_copy_string(reg
->func
, func
, sizeof(reg
->func
));
98 reg
->func
[sizeof(reg
->func
) - 1] = '\0';
104 reg
->next
= regions
[hash
];
106 reg
->fence
= FENCE_MAGIC
;
107 fence
= (ptr
+ reg
->len
);
108 put_unaligned_uint32(fence
, FENCE_MAGIC
);
110 ast_mutex_unlock(®lock
);
112 fprintf(stderr
, "Memory Allocation Failure - '%d' bytes in function %s at line %d of %s\n", (int) size
, func
, lineno
, file
);
114 fprintf(stderr
, "%ld - Memory Allocation Failure - '%d' bytes in function %s at line %d of %s\n", time(NULL
), (int) size
, func
, lineno
, file
);
121 static inline size_t __ast_sizeof_region(void *ptr
)
123 int hash
= HASH(ptr
);
124 struct ast_region
*reg
;
127 ast_mutex_lock(®lock
);
130 if (reg
->data
== ptr
) {
136 ast_mutex_unlock(®lock
);
140 static void __ast_free_region(void *ptr
, const char *file
, int lineno
, const char *func
)
142 int hash
= HASH(ptr
);
143 struct ast_region
*reg
, *prev
= NULL
;
146 ast_mutex_lock(®lock
);
149 if (reg
->data
== ptr
) {
151 prev
->next
= reg
->next
;
153 regions
[hash
] = reg
->next
;
160 ast_mutex_unlock(®lock
);
162 fence
= (unsigned int *)(reg
->data
+ reg
->len
);
163 if (reg
->fence
!= FENCE_MAGIC
) {
164 fprintf(stderr
, "WARNING: Low fence violation at %p, in %s of %s, line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
166 fprintf(mmlog
, "%ld - WARNING: Low fence violation at %p, in %s of %s, line %d\n", time(NULL
), reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
170 if (get_unaligned_uint32(fence
) != FENCE_MAGIC
) {
171 fprintf(stderr
, "WARNING: High fence violation at %p, in %s of %s, line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
173 fprintf(mmlog
, "%ld - WARNING: High fence violation at %p, in %s of %s, line %d\n", time(NULL
), reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
179 fprintf(stderr
, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", ptr
, func
, file
, lineno
);
181 fprintf(mmlog
, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL
), ptr
, func
, file
, lineno
);
187 void *__ast_calloc(size_t nmemb
, size_t size
, const char *file
, int lineno
, const char *func
)
190 if ((ptr
= __ast_alloc_region(size
* nmemb
, FUNC_CALLOC
, file
, lineno
, func
)))
191 memset(ptr
, 0, size
* nmemb
);
195 void *__ast_malloc(size_t size
, const char *file
, int lineno
, const char *func
)
197 return __ast_alloc_region(size
, FUNC_MALLOC
, file
, lineno
, func
);
200 void __ast_free(void *ptr
, const char *file
, int lineno
, const char *func
)
202 __ast_free_region(ptr
, file
, lineno
, func
);
205 void *__ast_realloc(void *ptr
, size_t size
, const char *file
, int lineno
, const char *func
)
209 if (ptr
&& !(len
= __ast_sizeof_region(ptr
))) {
210 fprintf(stderr
, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", ptr
, func
, file
, lineno
);
212 fprintf(mmlog
, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", time(NULL
), ptr
, func
, file
, lineno
);
217 if ((tmp
= __ast_alloc_region(size
, FUNC_REALLOC
, file
, lineno
, func
))) {
221 memcpy(tmp
, ptr
, len
);
222 __ast_free_region(ptr
, file
, lineno
, func
);
228 char *__ast_strdup(const char *s
, const char *file
, int lineno
, const char *func
)
235 if ((ptr
= __ast_alloc_region(len
, FUNC_STRDUP
, file
, lineno
, func
)))
240 char *__ast_strndup(const char *s
, size_t n
, const char *file
, int lineno
, const char *func
)
249 if ((ptr
= __ast_alloc_region(len
, FUNC_STRNDUP
, file
, lineno
, func
)))
254 int __ast_asprintf(const char *file
, int lineno
, const char *func
, char **strp
, const char *fmt
, ...)
263 size
= vsnprintf(&s
, 1, fmt
, ap2
);
265 if (!(*strp
= __ast_alloc_region(size
+ 1, FUNC_ASPRINTF
, file
, lineno
, func
))) {
269 vsnprintf(*strp
, size
+ 1, fmt
, ap
);
275 int __ast_vasprintf(char **strp
, const char *fmt
, va_list ap
, const char *file
, int lineno
, const char *func
)
283 size
= vsnprintf(&s
, 1, fmt
, ap2
);
285 if (!(*strp
= __ast_alloc_region(size
+ 1, FUNC_VASPRINTF
, file
, lineno
, func
))) {
289 vsnprintf(*strp
, size
+ 1, fmt
, ap
);
294 static int handle_show_memory(int fd
, int argc
, char *argv
[])
298 struct ast_region
*reg
;
299 unsigned int len
= 0;
305 /* try to lock applications list ... */
306 ast_mutex_lock(&showmemorylock
);
308 for (x
= 0; x
< SOME_PRIME
; x
++) {
311 if (!fn
|| !strcasecmp(fn
, reg
->file
) || !strcasecmp(fn
, "anomolies")) {
312 fence
= (unsigned int *)(reg
->data
+ reg
->len
);
313 if (reg
->fence
!= FENCE_MAGIC
) {
314 fprintf(stderr
, "WARNING: Low fence violation at %p, in %s of %s, line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
316 fprintf(mmlog
, "%ld - WARNING: Low fence violation at %p, in %s of %s, line %d\n", time(NULL
), reg
->data
, reg
->func
, reg
-> file
, reg
->lineno
);
320 if (get_unaligned_uint32(fence
) != FENCE_MAGIC
) {
321 fprintf(stderr
, "WARNING: High fence violation at %p, in %s of %s, line %d\n", reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
323 fprintf(mmlog
, "%ld - WARNING: High fence violation at %p, in %s of %s, line %d\n", time(NULL
), reg
->data
, reg
->func
, reg
->file
, reg
->lineno
);
328 if (!fn
|| !strcasecmp(fn
, reg
->file
)) {
329 ast_cli(fd
, "%10d bytes allocated in %20s at line %5d of %s\n", (int) reg
->len
, reg
->func
, reg
->lineno
, reg
->file
);
336 ast_cli(fd
, "%d bytes allocated %d units total\n", len
, count
);
337 ast_mutex_unlock(&showmemorylock
);
338 return RESULT_SUCCESS
;
341 struct file_summary
{
345 struct file_summary
*next
;
348 static int handle_show_memory_summary(int fd
, int argc
, char *argv
[])
352 struct ast_region
*reg
;
353 unsigned int len
= 0;
355 struct file_summary
*list
= NULL
, *cur
;
360 /* try to lock applications list ... */
361 ast_mutex_lock(®lock
);
363 for (x
= 0; x
< SOME_PRIME
; x
++) {
366 if (!fn
|| !strcasecmp(fn
, reg
->file
)) {
369 if ((!fn
&& !strcmp(cur
->fn
, reg
->file
)) || (fn
&& !strcmp(cur
->fn
, reg
->func
)))
374 cur
= alloca(sizeof(*cur
));
375 memset(cur
, 0, sizeof(*cur
));
376 ast_copy_string(cur
->fn
, fn
? reg
->func
: reg
->file
, sizeof(cur
->fn
));
380 cur
->len
+= reg
->len
;
386 ast_mutex_unlock(®lock
);
388 /* Dump the whole list */
392 count
+= list
->count
;
394 ast_cli(fd
, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list
->len
, list
->count
, list
->fn
, fn
);
396 ast_cli(fd
, "%10d bytes in %5d allocations in file '%s'\n", list
->len
, list
->count
, list
->fn
);
403 ast_cli(fd
, "%d bytes allocated %d units total\n", len
, count
);
404 return RESULT_SUCCESS
;
407 static char show_memory_help
[] =
408 "Usage: show memory allocations [<file>]\n"
409 " Dumps a list of all segments of allocated memory, optionally\n"
410 "limited to those from a specific file\n";
412 static char show_memory_summary_help
[] =
413 "Usage: show memory summary [<file>]\n"
414 " Summarizes heap memory allocations by file, or optionally\n"
415 "by function, if a file is specified\n";
417 static struct ast_cli_entry show_memory_allocations_cli
=
418 { { "show", "memory", "allocations", NULL
},
419 handle_show_memory
, "Display outstanding memory allocations",
422 static struct ast_cli_entry show_memory_summary_cli
=
423 { { "show", "memory", "summary", NULL
},
424 handle_show_memory_summary
, "Summarize outstanding memory allocations",
425 show_memory_summary_help
};
427 void __ast_mm_init(void)
429 char filename
[80] = "";
430 ast_cli_register(&show_memory_allocations_cli
);
431 ast_cli_register(&show_memory_summary_cli
);
433 snprintf(filename
, sizeof(filename
), "%s/mmlog", (char *)ast_config_AST_LOG_DIR
);
434 mmlog
= fopen(filename
, "a+");
436 ast_verbose("Asterisk Malloc Debugger Started (see %s))\n", filename
);
438 fprintf(mmlog
, "%ld - New session\n", time(NULL
));