2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2012, 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>
24 * \author Richard Mudgett <rmudgett@digium.com>
28 <support_level>core</support_level>
33 #if defined(__AST_DEBUG_MALLOC)
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
41 #include "asterisk/cli.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/strings.h"
44 #include "asterisk/unaligned.h"
47 * The larger the number the faster memory can be freed.
48 * However, more memory then is used for the regions[] hash
51 #define SOME_PRIME 1567
63 /* Undefine all our macros */
73 #define FENCE_MAGIC 0xdeadbeef /*!< Allocated memory high/low fence overwrite check. */
74 #define FREED_MAGIC 0xdeaddead /*!< Freed memory wipe filler. */
75 #define MALLOC_FILLER 0x55 /*!< Malloced memory filler. Must not be zero. */
80 AST_LIST_ENTRY(ast_region) node;
82 unsigned int cache; /* region was allocated as part of a cache pool */
89 * \brief Lower guard fence.
91 * \note Must be right before data[].
93 * \note Padding between fence and data[] is irrelevent because
94 * data[] is used to fill in the lower fence check value and not
95 * the fence member. The fence member is to ensure that there
96 * is space reserved for the fence check value.
100 * \brief Location of the requested malloc block to return.
102 * \note Must have the same alignment that malloc returns.
103 * i.e., It is suitably aligned for any kind of varible.
105 unsigned char data[0] __attribute__((aligned));
108 /*! Hash table of lists of active allocated memory regions. */
109 static struct ast_region *regions[SOME_PRIME];
111 /*! Number of freed regions to keep around to delay actually freeing them. */
112 #define FREED_MAX_COUNT 1500
114 /*! Maximum size of a minnow block */
115 #define MINNOWS_MAX_SIZE 50
117 struct ast_freed_regions {
118 /*! Memory regions that have been freed. */
119 struct ast_region *regions[FREED_MAX_COUNT];
120 /*! Next index into freed regions[] to use. */
124 /*! Large memory blocks that have been freed. */
125 static struct ast_freed_regions whales;
126 /*! Small memory blocks that have been freed. */
127 static struct ast_freed_regions minnows;
130 /*! No summary at exit. */
132 /*! Bit set if summary by line at exit. */
133 SUMMARY_BY_LINE = (1 << 0),
134 /*! Bit set if summary by function at exit. */
135 SUMMARY_BY_FUNC = (1 << 1),
136 /*! Bit set if summary by file at exit. */
137 SUMMARY_BY_FILE = (1 << 2),
140 /*! Summary options of unfreed regions at exit. */
141 static enum summary_opts atexit_summary;
142 /*! Nonzero if the unfreed regions are listed at exit. */
143 static int atexit_list;
145 #define HASH(a) (((unsigned long)(a)) % ARRAY_LEN(regions))
147 /*! Tracking this mutex will cause infinite recursion, as the mutex tracking
148 * code allocates memory */
149 AST_MUTEX_DEFINE_STATIC_NOTRACKING(reglock);
151 #define astmm_log(...) \
153 fprintf(stderr, __VA_ARGS__); \
155 fprintf(mmlog, __VA_ARGS__); \
163 * \note If DO_CRASH is not defined then the function returns.
167 static void my_do_crash(void)
170 * Give the logger a chance to get the message out, just in case
171 * we abort(), or Asterisk crashes due to whatever problem just
178 static void *__ast_alloc_region(size_t size, const enum func_type which, const char *file, int lineno, const char *func, unsigned int cache)
180 struct ast_region *reg;
184 if (!(reg = malloc(size + sizeof(*reg) + sizeof(*fence)))) {
185 astmm_log("Memory Allocation Failure - '%d' bytes at %s %s() line %d\n",
186 (int) size, file, func, lineno);
192 reg->lineno = lineno;
194 ast_copy_string(reg->file, file, sizeof(reg->file));
195 ast_copy_string(reg->func, func, sizeof(reg->func));
200 * We use the bytes just preceeding reg->data and not reg->fence
201 * because there is likely to be padding between reg->fence and
202 * reg->data for reg->data alignment.
204 fence = (unsigned int *) (reg->data - sizeof(*fence));
205 *fence = FENCE_MAGIC;
207 /* Init higher fence. */
208 fence = (unsigned int *) (reg->data + reg->len);
209 put_unaligned_uint32(fence, FENCE_MAGIC);
211 hash = HASH(reg->data);
212 ast_mutex_lock(®lock);
213 AST_LIST_NEXT(reg, node) = regions[hash];
215 ast_mutex_unlock(®lock);
222 * \brief Wipe the region payload data with a known value.
224 * \param reg Region block to be wiped.
228 static void region_data_wipe(struct ast_region *reg)
234 * Wipe the lower fence, the payload, and whatever amount of the
235 * higher fence that falls into alignment with the payload.
237 end = reg->data + reg->len;
238 for (pos = ®->fence; (void *) pos <= end; ++pos) {
245 * \brief Check the region payload data for memory corruption.
247 * \param reg Region block to be checked.
251 static void region_data_check(struct ast_region *reg)
257 * Check the lower fence, the payload, and whatever amount of
258 * the higher fence that falls into alignment with the payload.
260 end = reg->data + reg->len;
261 for (pos = ®->fence; (void *) pos <= end; ++pos) {
262 if (*pos != FREED_MAGIC) {
263 astmm_log("WARNING: Memory corrupted after free of %p allocated at %s %s() line %d\n",
264 reg->data, reg->file, reg->func, reg->lineno);
273 * \brief Flush the circular array of freed regions.
275 * \param freed Already freed region blocks storage.
279 static void freed_regions_flush(struct ast_freed_regions *freed)
282 struct ast_region *old;
284 ast_mutex_lock(®lock);
285 for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) {
286 old = freed->regions[idx];
287 freed->regions[idx] = NULL;
289 region_data_check(old);
294 ast_mutex_unlock(®lock);
299 * \brief Delay freeing a region block.
301 * \param freed Already freed region blocks storage.
302 * \param reg Region block to be freed.
306 static void region_free(struct ast_freed_regions *freed, struct ast_region *reg)
308 struct ast_region *old;
310 region_data_wipe(reg);
312 ast_mutex_lock(®lock);
313 old = freed->regions[freed->index];
314 freed->regions[freed->index] = reg;
317 if (ARRAY_LEN(freed->regions) <= freed->index) {
320 ast_mutex_unlock(®lock);
323 region_data_check(old);
330 * \brief Remove a region from the active regions.
332 * \param ptr Region payload data pointer.
334 * \retval region on success.
335 * \retval NULL if not found.
337 static struct ast_region *region_remove(void *ptr)
340 struct ast_region *reg;
341 struct ast_region *prev = NULL;
345 ast_mutex_lock(®lock);
346 for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) {
347 if (reg->data == ptr) {
349 AST_LIST_NEXT(prev, node) = AST_LIST_NEXT(reg, node);
351 regions[hash] = AST_LIST_NEXT(reg, node);
357 ast_mutex_unlock(®lock);
364 * \brief Check the fences of a region.
366 * \param reg Region block to check.
370 static void region_check_fences(struct ast_region *reg)
375 * We use the bytes just preceeding reg->data and not reg->fence
376 * because there is likely to be padding between reg->fence and
377 * reg->data for reg->data alignment.
379 fence = (unsigned int *) (reg->data - sizeof(*fence));
380 if (*fence != FENCE_MAGIC) {
381 astmm_log("WARNING: Low fence violation of %p allocated at %s %s() line %d\n",
382 reg->data, reg->file, reg->func, reg->lineno);
385 fence = (unsigned int *) (reg->data + reg->len);
386 if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
387 astmm_log("WARNING: High fence violation of %p allocated at %s %s() line %d\n",
388 reg->data, reg->file, reg->func, reg->lineno);
395 * \brief Check the fences of all regions currently allocated.
399 static void regions_check_all_fences(void)
402 struct ast_region *reg;
404 ast_mutex_lock(®lock);
405 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
406 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
407 region_check_fences(reg);
410 ast_mutex_unlock(®lock);
413 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
415 struct ast_region *reg;
421 reg = region_remove(ptr);
423 region_check_fences(reg);
425 if (reg->len <= MINNOWS_MAX_SIZE) {
426 region_free(&minnows, reg);
428 region_free(&whales, reg);
432 * This memory region is not registered. It could be because of
433 * a double free or the memory block was not allocated by the
436 astmm_log("WARNING: Freeing unregistered memory %p by %s %s() line %d\n",
437 ptr, file, func, lineno);
442 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
446 ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 0);
448 memset(ptr, 0, size * nmemb);
454 void *__ast_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
458 ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 1);
460 memset(ptr, 0, size * nmemb);
466 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
470 ptr = __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func, 0);
472 /* Make sure that the malloced memory is not zero. */
473 memset(ptr, MALLOC_FILLER, size);
479 void __ast_free(void *ptr, const char *file, int lineno, const char *func)
481 __ast_free_region(ptr, file, lineno, func);
485 * \note reglock must be locked before calling.
487 static struct ast_region *region_find(void *ptr)
490 struct ast_region *reg;
493 for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) {
494 if (reg->data == ptr) {
502 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
505 struct ast_region *found;
509 ast_mutex_lock(®lock);
510 found = region_find(ptr);
512 ast_mutex_unlock(®lock);
513 astmm_log("WARNING: Realloc of unregistered memory %p by %s %s() line %d\n",
514 ptr, file, func, lineno);
519 ast_mutex_unlock(®lock);
526 __ast_free_region(ptr, file, lineno, func);
530 new_mem = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func, 0);
533 /* Copy the old data to the new malloced memory. */
535 memcpy(new_mem, ptr, size);
537 memcpy(new_mem, ptr, len);
538 /* Make sure that the added memory is not zero. */
539 memset(new_mem + len, MALLOC_FILLER, size - len);
541 __ast_free_region(ptr, file, lineno, func);
543 /* Make sure that the malloced memory is not zero. */
544 memset(new_mem, MALLOC_FILLER, size);
551 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
560 if ((ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func, 0)))
566 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
576 if ((ptr = __ast_alloc_region(len + 1, FUNC_STRNDUP, file, lineno, func, 0))) {
584 int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *fmt, ...)
593 size = vsnprintf(&s, 1, fmt, ap2);
595 if (!(*strp = __ast_alloc_region(size + 1, FUNC_ASPRINTF, file, lineno, func, 0))) {
599 vsnprintf(*strp, size + 1, fmt, ap);
605 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func)
613 size = vsnprintf(&s, 1, fmt, ap2);
615 if (!(*strp = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func, 0))) {
619 vsnprintf(*strp, size + 1, fmt, ap);
624 static char *handle_memory_atexit_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
628 e->command = "memory atexit list";
630 "Usage: memory atexit list {on|off}\n"
631 " Enable dumping a list of still allocated memory segments at exit.\n";
635 const char * const options[] = { "off", "on", NULL };
637 return ast_cli_complete(a->word, options, a->n);
643 return CLI_SHOWUSAGE;
646 if (ast_true(a->argv[3])) {
648 } else if (ast_false(a->argv[3])) {
651 return CLI_SHOWUSAGE;
654 ast_cli(a->fd, "The atexit list is: %s\n", atexit_list ? "On" : "Off");
659 static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
665 e->command = "memory atexit summary";
667 "Usage: memory atexit summary {off|byline|byfunc|byfile}\n"
668 " Summary of still allocated memory segments at exit options.\n"
669 " off - Disable at exit summary.\n"
670 " byline - Enable at exit summary by file line number.\n"
671 " byfunc - Enable at exit summary by function name.\n"
672 " byfile - Enable at exit summary by file.\n"
674 " Note: byline, byfunc, and byfile are cumulative enables.\n";
678 const char * const options[] = { "off", "byline", "byfunc", "byfile", NULL };
680 return ast_cli_complete(a->word, options, a->n);
686 return CLI_SHOWUSAGE;
689 if (ast_false(a->argv[3])) {
690 atexit_summary = SUMMARY_OFF;
691 } else if (!strcasecmp(a->argv[3], "byline")) {
692 atexit_summary |= SUMMARY_BY_LINE;
693 } else if (!strcasecmp(a->argv[3], "byfunc")) {
694 atexit_summary |= SUMMARY_BY_FUNC;
695 } else if (!strcasecmp(a->argv[3], "byfile")) {
696 atexit_summary |= SUMMARY_BY_FILE;
698 return CLI_SHOWUSAGE;
701 if (atexit_summary) {
703 if (atexit_summary & SUMMARY_BY_LINE) {
704 strcat(buf, "byline");
706 if (atexit_summary & SUMMARY_BY_FUNC) {
710 strcat(buf, "byfunc");
712 if (atexit_summary & SUMMARY_BY_FILE) {
716 strcat(buf, "byfile");
721 ast_cli(a->fd, "The atexit summary is: %s\n", buf);
726 static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
728 const char *fn = NULL;
729 struct ast_region *reg;
731 unsigned int len = 0;
732 unsigned int cache_len = 0;
733 unsigned int count = 0;
737 e->command = "memory show allocations";
739 "Usage: memory show allocations [<file>|anomalies]\n"
740 " Dumps a list of segments of allocated memory.\n"
741 " Defaults to listing all memory allocations.\n"
742 " <file> - Restricts output to memory allocated by the file.\n"
743 " anomalies - Only check for fence violations.\n";
751 } else if (a->argc != 3) {
752 return CLI_SHOWUSAGE;
755 /* Look for historical misspelled option as well. */
756 if (fn && (!strcasecmp(fn, "anomalies") || !strcasecmp(fn, "anomolies"))) {
757 regions_check_all_fences();
758 ast_cli(a->fd, "Anomaly check complete.\n");
762 ast_mutex_lock(®lock);
763 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
764 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
765 if (fn && strcasecmp(fn, reg->file)) {
769 region_check_fences(reg);
771 ast_cli(a->fd, "%10u bytes allocated%s by %20s() line %5u of %s\n",
772 (unsigned int) reg->len, reg->cache ? " (cache)" : "",
773 reg->func, reg->lineno, reg->file);
777 cache_len += reg->len;
782 ast_mutex_unlock(®lock);
785 ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n",
786 len, cache_len, count);
788 ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count);
794 static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
796 #define my_max(a, b) ((a) >= (b) ? (a) : (b))
798 const char *fn = NULL;
801 struct ast_region *reg;
802 unsigned int len = 0;
803 unsigned int cache_len = 0;
804 unsigned int count = 0;
805 struct file_summary {
806 struct file_summary *next;
808 unsigned int cache_len;
811 char name[my_max(sizeof(reg->file), sizeof(reg->func))];
812 } *list = NULL, *cur, **prev;
816 e->command = "memory show summary";
818 "Usage: memory show summary [<file>]\n"
819 " Summarizes heap memory allocations by file, or optionally\n"
820 " by line, if a file is specified.\n";
828 } else if (a->argc != 3) {
829 return CLI_SHOWUSAGE;
832 ast_mutex_lock(®lock);
833 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
834 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
836 if (strcasecmp(fn, reg->file)) {
840 /* Sort list by func/lineno. Find existing or place to insert. */
841 for (prev = &list; (cur = *prev); prev = &cur->next) {
842 cmp = strcmp(cur->name, reg->func);
847 /* Insert before current */
851 cmp = cur->lineno - reg->lineno;
856 /* Insert before current */
862 /* Sort list by filename. Find existing or place to insert. */
863 for (prev = &list; (cur = *prev); prev = &cur->next) {
864 cmp = strcmp(cur->name, reg->file);
869 /* Insert before current */
877 cur = ast_alloca(sizeof(*cur));
878 memset(cur, 0, sizeof(*cur));
879 cur->lineno = reg->lineno;
880 ast_copy_string(cur->name, fn ? reg->func : reg->file, sizeof(cur->name));
886 cur->len += reg->len;
888 cur->cache_len += reg->len;
893 ast_mutex_unlock(®lock);
895 /* Dump the whole list */
896 for (cur = list; cur; cur = cur->next) {
898 cache_len += cur->cache_len;
900 if (cur->cache_len) {
902 ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations by %20s() line %5u of %s\n",
903 cur->len, cur->cache_len, cur->count, cur->name, cur->lineno, fn);
905 ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations in file %s\n",
906 cur->len, cur->cache_len, cur->count, cur->name);
910 ast_cli(a->fd, "%10u bytes in %10u allocations by %20s() line %5u of %s\n",
911 cur->len, cur->count, cur->name, cur->lineno, fn);
913 ast_cli(a->fd, "%10u bytes in %10u allocations in file %s\n",
914 cur->len, cur->count, cur->name);
920 ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n",
921 len, cache_len, count);
923 ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count);
929 static struct ast_cli_entry cli_memory[] = {
930 AST_CLI_DEFINE(handle_memory_atexit_list, "Enable memory allocations not freed at exit list."),
931 AST_CLI_DEFINE(handle_memory_atexit_summary, "Enable memory allocations not freed at exit summary."),
932 AST_CLI_DEFINE(handle_memory_show_allocations, "Display outstanding memory allocations"),
933 AST_CLI_DEFINE(handle_memory_show_summary, "Summarize outstanding memory allocations"),
936 AST_LIST_HEAD_NOLOCK(region_list, ast_region);
940 * \brief Convert the allocated regions hash table to a list.
942 * \param list Fill list with the allocated regions.
945 * Take all allocated regions from the regions[] and put them
948 * \note reglock must be locked before calling.
950 * \note This function is destructive to the regions[] lists.
952 * \return Length of list created.
954 static size_t mm_atexit_hash_list(struct region_list *list)
956 struct ast_region *reg;
961 for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
962 while ((reg = regions[idx])) {
963 regions[idx] = AST_LIST_NEXT(reg, node);
964 AST_LIST_NEXT(reg, node) = NULL;
965 AST_LIST_INSERT_HEAD(list, reg, node);
974 * \brief Put the regions list into the allocated regions hash table.
976 * \param list List to put into the allocated regions hash table.
978 * \note reglock must be locked before calling.
982 static void mm_atexit_hash_restore(struct region_list *list)
984 struct ast_region *reg;
987 while ((reg = AST_LIST_REMOVE_HEAD(list, node))) {
988 hash = HASH(reg->data);
989 AST_LIST_NEXT(reg, node) = regions[hash];
996 * \brief Sort regions comparision.
998 * \param left Region to compare.
999 * \param right Region to compare.
1001 * \retval <0 if left < right
1002 * \retval =0 if left == right
1003 * \retval >0 if left > right
1005 static int mm_atexit_cmp(struct ast_region *left, struct ast_region *right)
1011 /* Sort by filename. */
1012 cmp = strcmp(left->file, right->file);
1017 /* Sort by line number. */
1018 cmp = left->lineno - right->lineno;
1023 /* Sort by allocated size. */
1024 cmp_size = left->len - right->len;
1032 /* Sort by allocated pointers just because. */
1033 cmp_ptr = left->data - right->data;
1046 * \brief Merge the given sorted sublists into sorted order onto the end of the list.
1048 * \param list Merge sublists onto this list.
1049 * \param sub1 First sublist to merge.
1050 * \param sub2 Second sublist to merge.
1054 static void mm_atexit_list_merge(struct region_list *list, struct region_list *sub1, struct region_list *sub2)
1056 struct ast_region *reg;
1059 if (AST_LIST_EMPTY(sub1)) {
1060 /* The remaining sublist goes onto the list. */
1061 AST_LIST_APPEND_LIST(list, sub2, node);
1064 if (AST_LIST_EMPTY(sub2)) {
1065 /* The remaining sublist goes onto the list. */
1066 AST_LIST_APPEND_LIST(list, sub1, node);
1070 if (mm_atexit_cmp(AST_LIST_FIRST(sub1), AST_LIST_FIRST(sub2)) <= 0) {
1071 reg = AST_LIST_REMOVE_HEAD(sub1, node);
1073 reg = AST_LIST_REMOVE_HEAD(sub2, node);
1075 AST_LIST_INSERT_TAIL(list, reg, node);
1081 * \brief Take sublists off of the given list.
1083 * \param list Source list to remove sublists from the beginning of list.
1084 * \param sub Array of sublists to fill. (Lists are empty on entry.)
1085 * \param num_lists Number of lists to remove from the source list.
1086 * \param size Size of the sublists to remove.
1087 * \param remaining Remaining number of elements on the source list.
1091 static void mm_atexit_list_split(struct region_list *list, struct region_list sub[], size_t num_lists, size_t size, size_t *remaining)
1095 for (idx = 0; idx < num_lists; ++idx) {
1098 if (*remaining < size) {
1099 /* The remaining source list goes onto the sublist. */
1100 AST_LIST_APPEND_LIST(&sub[idx], list, node);
1105 /* Take a sublist off the beginning of the source list. */
1107 for (count = size; count--;) {
1108 struct ast_region *reg;
1110 reg = AST_LIST_REMOVE_HEAD(list, node);
1111 AST_LIST_INSERT_TAIL(&sub[idx], reg, node);
1118 * \brief Sort the regions list using mergesort.
1120 * \param list Allocated regions list to sort.
1121 * \param length Length of the list.
1125 static void mm_atexit_list_sort(struct region_list *list, size_t length)
1127 /*! Semi-sorted merged list. */
1128 struct region_list merged = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1129 /*! Sublists to merge. (Can only merge two sublists at this time.) */
1130 struct region_list sub[2] = {
1131 AST_LIST_HEAD_NOLOCK_INIT_VALUE,
1132 AST_LIST_HEAD_NOLOCK_INIT_VALUE
1134 /*! Sublist size. */
1136 /*! Remaining elements in the list. */
1138 /*! Number of sublist merge passes to process the list. */
1145 while (!AST_LIST_EMPTY(list)) {
1146 mm_atexit_list_split(list, sub, ARRAY_LEN(sub), size, &remaining);
1147 mm_atexit_list_merge(&merged, &sub[0], &sub[1]);
1150 AST_LIST_APPEND_LIST(list, &merged, node);
1152 /* The list is now sorted. */
1156 /* Double the sublist size to remove for next round. */
1163 * \brief List all regions currently allocated.
1165 * \param alloced regions list.
1169 static void mm_atexit_regions_list(struct region_list *alloced)
1171 struct ast_region *reg;
1173 AST_LIST_TRAVERSE(alloced, reg, node) {
1174 astmm_log("%s %s() line %u: %u bytes%s at %p\n",
1175 reg->file, reg->func, reg->lineno,
1176 (unsigned int) reg->len, reg->cache ? " (cache)" : "", reg->data);
1182 * \brief Summarize all regions currently allocated.
1184 * \param alloced Sorted regions list.
1188 static void mm_atexit_regions_summary(struct region_list *alloced)
1190 struct ast_region *reg;
1191 struct ast_region *next;
1195 unsigned int cache_len;
1196 } by_line, by_func, by_file, total;
1200 by_line.cache_len = 0;
1204 by_func.cache_len = 0;
1208 by_file.cache_len = 0;
1212 total.cache_len = 0;
1214 AST_LIST_TRAVERSE(alloced, reg, node) {
1215 next = AST_LIST_NEXT(reg, node);
1218 by_line.len += reg->len;
1220 by_line.cache_len += reg->len;
1222 if (next && !strcmp(reg->file, next->file) && reg->lineno == next->lineno) {
1225 if (atexit_summary & SUMMARY_BY_LINE) {
1226 if (by_line.cache_len) {
1227 astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s() line %u\n",
1228 by_line.len, by_line.cache_len, by_line.count, reg->file, reg->func, reg->lineno);
1230 astmm_log("%10u bytes in %5u allocations. %s %s() line %u\n",
1231 by_line.len, by_line.count, reg->file, reg->func, reg->lineno);
1235 by_func.count += by_line.count;
1236 by_func.len += by_line.len;
1237 by_func.cache_len += by_line.cache_len;
1240 by_line.cache_len = 0;
1241 if (next && !strcmp(reg->file, next->file) && !strcmp(reg->func, next->func)) {
1244 if (atexit_summary & SUMMARY_BY_FUNC) {
1245 if (by_func.cache_len) {
1246 astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s()\n",
1247 by_func.len, by_func.cache_len, by_func.count, reg->file, reg->func);
1249 astmm_log("%10u bytes in %5u allocations. %s %s()\n",
1250 by_func.len, by_func.count, reg->file, reg->func);
1254 by_file.count += by_func.count;
1255 by_file.len += by_func.len;
1256 by_file.cache_len += by_func.cache_len;
1259 by_func.cache_len = 0;
1260 if (next && !strcmp(reg->file, next->file)) {
1263 if (atexit_summary & SUMMARY_BY_FILE) {
1264 if (by_file.cache_len) {
1265 astmm_log("%10u bytes (%u in caches) in %u allocations. %s\n",
1266 by_file.len, by_file.cache_len, by_file.count, reg->file);
1268 astmm_log("%10u bytes in %5u allocations. %s\n",
1269 by_file.len, by_file.count, reg->file);
1273 total.count += by_file.count;
1274 total.len += by_file.len;
1275 total.cache_len += by_file.cache_len;
1278 by_file.cache_len = 0;
1281 if (total.cache_len) {
1282 astmm_log("%u bytes (%u in caches) in %u allocations.\n",
1283 total.len, total.cache_len, total.count);
1285 astmm_log("%u bytes in %u allocations.\n", total.len, total.count);
1291 * \brief Dump the memory allocations atexit.
1293 * \note reglock must be locked before calling.
1297 static void mm_atexit_dump(void)
1299 struct region_list alloced_atexit = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1302 length = mm_atexit_hash_list(&alloced_atexit);
1304 /* Wow! This is amazing! */
1305 astmm_log("Exiting with all memory freed.\n");
1309 mm_atexit_list_sort(&alloced_atexit, length);
1311 astmm_log("Exiting with the following memory not freed:\n");
1313 mm_atexit_regions_list(&alloced_atexit);
1315 if (atexit_summary) {
1316 mm_atexit_regions_summary(&alloced_atexit);
1320 * Put the alloced list back into regions[].
1322 * We have do do this because we can get called before all other
1323 * threads have terminated.
1325 mm_atexit_hash_restore(&alloced_atexit);
1332 static void mm_atexit_final(void)
1336 fprintf(stderr, "Waiting 10 seconds to let other threads die.\n");
1339 regions_check_all_fences();
1341 /* Flush all delayed memory free circular arrays. */
1342 freed_regions_flush(&whales);
1343 freed_regions_flush(&minnows);
1345 /* Peform atexit allocation dumps. */
1346 if (atexit_list || atexit_summary) {
1347 ast_mutex_lock(®lock);
1349 ast_mutex_unlock(®lock);
1352 /* Close the log file. */
1361 * \brief Initialize malloc debug phase 1.
1363 * \note Must be called first thing in main().
1367 void __ast_mm_init_phase_1(void)
1369 atexit(mm_atexit_final);
1376 static void mm_atexit_ast(void)
1378 ast_cli_unregister_multiple(cli_memory, ARRAY_LEN(cli_memory));
1382 * \brief Initialize malloc debug phase 2.
1386 void __ast_mm_init_phase_2(void)
1388 char filename[PATH_MAX];
1390 ast_cli_register_multiple(cli_memory, ARRAY_LEN(cli_memory));
1392 snprintf(filename, sizeof(filename), "%s/mmlog", ast_config_AST_LOG_DIR);
1394 ast_verb(1, "Asterisk Malloc Debugger Started (see %s))\n", filename);
1396 mmlog = fopen(filename, "a+");
1398 fprintf(mmlog, "%ld - New session\n", (long) time(NULL));
1401 ast_log(LOG_ERROR, "Could not open malloc debug log file: %s\n", filename);
1404 ast_register_atexit(mm_atexit_ast);
1407 #endif /* defined(__AST_DEBUG_MALLOC) */