CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / astmm.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2012, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Memory Management
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * \author Richard Mudgett <rmudgett@digium.com>
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #define ASTMM_LIBC ASTMM_IGNORE
32 #include "asterisk.h"
33
34 #include "asterisk/_private.h"
35 #include "asterisk/logger.h"
36
37 /*!
38  * \brief DEBUG_CHAOS returns failure randomly
39  *
40  * DEBUG_CHAOS_RETURN(failure); can be used to fake
41  * failure of functions such as memory allocation,
42  * for the purposes of testing failure handling.
43  */
44 #ifdef DEBUG_CHAOS
45 #ifndef DEBUG_CHAOS_ALLOC_CHANCE
46 #define DEBUG_CHAOS_ALLOC_CHANCE 100000
47 #endif
48 /* Could #define DEBUG_CHAOS_ENABLE ast_fully_booted */
49 #ifndef DEBUG_CHAOS_ENABLE
50 #define DEBUG_CHAOS_ENABLE 1
51 #endif
52 #define DEBUG_CHAOS_RETURN(CHANCE, FAILURE) \
53         do { \
54                 if ((DEBUG_CHAOS_ENABLE) && (ast_random() % CHANCE == 0)) { \
55                         return FAILURE; \
56                 } \
57         } while (0)
58 #else
59 #define DEBUG_CHAOS_RETURN(c,f)
60 #endif
61
62 #if defined(STANDALONE) || defined(STANDALONE2)
63 #define ast_log_safe ast_log
64 #endif
65
66 #if defined(MALLOC_DEBUG) && !defined(STANDALONE) && !defined(STANDALONE2)
67 #define __AST_DEBUG_MALLOC
68 #endif
69
70 #define MALLOC_FAILURE_MSG \
71         ast_log_safe(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file)
72
73 #if defined(__AST_DEBUG_MALLOC)
74
75 #include "asterisk/paths.h"     /* use ast_config_AST_LOG_DIR */
76 #include <stddef.h>
77 #include <time.h>
78
79 #include "asterisk/cli.h"
80 #include "asterisk/lock.h"
81 #include "asterisk/strings.h"
82 #include "asterisk/unaligned.h"
83 #include "asterisk/backtrace.h"
84
85 /*!
86  * The larger the number the faster memory can be freed.
87  * However, more memory then is used for the regions[] hash
88  * table.
89  */
90 #define SOME_PRIME 1567
91
92 enum func_type {
93         FUNC_CALLOC = 1,
94         FUNC_MALLOC,
95         FUNC_REALLOC,
96         FUNC_STRDUP,
97         FUNC_STRNDUP,
98         FUNC_VASPRINTF,
99         FUNC_ASPRINTF
100 };
101
102 #define FENCE_MAGIC             0xfeedbabe      /*!< Allocated memory high/low fence overwrite check. */
103 #define FREED_MAGIC             0xdeaddead      /*!< Freed memory wipe filler. */
104 #define MALLOC_FILLER   0x55            /*!< Malloced memory filler.  Must not be zero. */
105
106 static FILE *mmlog;
107
108 struct ast_region {
109         AST_LIST_ENTRY(ast_region) node;
110         struct ast_bt *bt;
111         size_t len;
112         unsigned int cache;             /* region was allocated as part of a cache pool */
113         unsigned int lineno;
114         enum func_type which;
115         char file[64];
116         char func[40];
117         /*!
118          * \brief Lower guard fence.
119          *
120          * \note Must be right before data[].
121          *
122          * \note Padding between fence and data[] is irrelevent because
123          * data[] is used to fill in the lower fence check value and not
124          * the fence member.  The fence member is to ensure that there
125          * is space reserved for the fence check value.
126          */
127         unsigned int fence;
128         /*!
129          * \brief Location of the requested malloc block to return.
130          *
131          * \note Must have the same alignment that malloc returns.
132          * i.e., It is suitably aligned for any kind of varible.
133          */
134         unsigned char data[0] __attribute__((aligned));
135 };
136
137 /*! Hash table of lists of active allocated memory regions. */
138 static struct ast_region *regions[SOME_PRIME];
139
140 /*! Number of freed regions to keep around to delay actually freeing them. */
141 #define FREED_MAX_COUNT         1500
142
143 /*! Maximum size of a minnow block */
144 #define MINNOWS_MAX_SIZE        50
145
146 struct ast_freed_regions {
147         /*! Memory regions that have been freed. */
148         struct ast_region *regions[FREED_MAX_COUNT];
149         /*! Next index into freed regions[] to use. */
150         int index;
151 };
152
153 /*! Large memory blocks that have been freed. */
154 static struct ast_freed_regions whales;
155 /*! Small memory blocks that have been freed. */
156 static struct ast_freed_regions minnows;
157
158 enum summary_opts {
159         /*! No summary at exit. */
160         SUMMARY_OFF,
161         /*! Bit set if summary by line at exit. */
162         SUMMARY_BY_LINE = (1 << 0),
163         /*! Bit set if summary by function at exit. */
164         SUMMARY_BY_FUNC = (1 << 1),
165         /*! Bit set if summary by file at exit. */
166         SUMMARY_BY_FILE = (1 << 2),
167 };
168
169 /*! Summary options of unfreed regions at exit. */
170 static enum summary_opts atexit_summary;
171 /*! Nonzero if the unfreed regions are listed at exit. */
172 static int atexit_list;
173 /*! Nonzero if the memory allocation backtrace is enabled. */
174 static int backtrace_enabled;
175
176 #define HASH(a)         (((unsigned long)(a)) % ARRAY_LEN(regions))
177
178 /*! Tracking this mutex will cause infinite recursion, as the mutex tracking
179  *  code allocates memory */
180 AST_MUTEX_DEFINE_STATIC_NOTRACKING(reglock);
181
182 #define astmm_log(...)                               \
183         do {                                         \
184                 fprintf(stderr, __VA_ARGS__);        \
185                 if (mmlog) {                         \
186                         fprintf(mmlog, __VA_ARGS__); \
187                         fflush(mmlog);               \
188                 }                                    \
189         } while (0)
190
191 static void print_backtrace(struct ast_bt *bt)
192 {
193         int i = 0;
194         struct ast_vector_string *strings;
195
196         if (!bt) {
197                 return;
198         }
199
200         if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
201                 astmm_log("Memory allocation backtrace:\n");
202                 for (i = 3; i < AST_VECTOR_SIZE(strings) - 2; i++) {
203                         astmm_log("#%d: %s\n", i - 3, AST_VECTOR_GET(strings, i));
204                 }
205                 ast_bt_free_symbols(strings);
206         }
207 }
208
209 /*!
210  * \internal
211  *
212  * \note If DO_CRASH is not defined then the function returns.
213  *
214  * \return Nothing
215  */
216 static void my_do_crash(void)
217 {
218         /*
219          * Give the logger a chance to get the message out, just in case
220          * we abort(), or Asterisk crashes due to whatever problem just
221          * happened.
222          */
223         usleep(1);
224         ast_do_crash();
225 }
226
227 static void *__ast_alloc_region(size_t size, const enum func_type which, const char *file, int lineno, const char *func, unsigned int cache)
228 {
229         struct ast_region *reg;
230         unsigned int *fence;
231         int hash;
232
233         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
234
235         if (!(reg = malloc(size + sizeof(*reg) + sizeof(*fence)))) {
236                 astmm_log("Memory Allocation Failure - '%d' bytes at %s %s() line %d\n",
237                         (int) size, file, func, lineno);
238                 return NULL;
239         }
240
241         reg->len = size;
242         reg->cache = cache;
243         reg->lineno = lineno;
244         reg->which = which;
245         reg->bt = backtrace_enabled ? ast_bt_create() : NULL;
246         ast_copy_string(reg->file, file, sizeof(reg->file));
247         ast_copy_string(reg->func, func, sizeof(reg->func));
248
249         /*
250          * Init lower fence.
251          *
252          * We use the bytes just preceeding reg->data and not reg->fence
253          * because there is likely to be padding between reg->fence and
254          * reg->data for reg->data alignment.
255          */
256         fence = (unsigned int *) (reg->data - sizeof(*fence));
257         *fence = FENCE_MAGIC;
258
259         /* Init higher fence. */
260         fence = (unsigned int *) (reg->data + reg->len);
261         put_unaligned_uint32(fence, FENCE_MAGIC);
262
263         hash = HASH(reg->data);
264         ast_mutex_lock(&reglock);
265         AST_LIST_NEXT(reg, node) = regions[hash];
266         regions[hash] = reg;
267         ast_mutex_unlock(&reglock);
268
269         return reg->data;
270 }
271
272 /*!
273  * \internal
274  * \brief Wipe the region payload data with a known value.
275  *
276  * \param reg Region block to be wiped.
277  *
278  * \return Nothing
279  */
280 static void region_data_wipe(struct ast_region *reg)
281 {
282         void *end;
283         unsigned int *pos;
284
285         /*
286          * Wipe the lower fence, the payload, and whatever amount of the
287          * higher fence that falls into alignment with the payload.
288          */
289         end = reg->data + reg->len;
290         for (pos = &reg->fence; (void *) pos <= end; ++pos) {
291                 *pos = FREED_MAGIC;
292         }
293 }
294
295 /*!
296  * \internal
297  * \brief Check the region payload data for memory corruption.
298  *
299  * \param reg Region block to be checked.
300  *
301  * \return Nothing
302  */
303 static void region_data_check(struct ast_region *reg)
304 {
305         void *end;
306         unsigned int *pos;
307
308         /*
309          * Check the lower fence, the payload, and whatever amount of
310          * the higher fence that falls into alignment with the payload.
311          */
312         end = reg->data + reg->len;
313         for (pos = &reg->fence; (void *) pos <= end; ++pos) {
314                 if (*pos != FREED_MAGIC) {
315                         astmm_log("WARNING: Memory corrupted after free of %p allocated at %s %s() line %d\n",
316                                 reg->data, reg->file, reg->func, reg->lineno);
317                         print_backtrace(reg->bt);
318                         my_do_crash();
319                         break;
320                 }
321         }
322 }
323
324 /*!
325  * \internal
326  * \brief Flush the circular array of freed regions.
327  *
328  * \param freed Already freed region blocks storage.
329  *
330  * \return Nothing
331  */
332 static void freed_regions_flush(struct ast_freed_regions *freed)
333 {
334         int idx;
335         struct ast_region *old;
336
337         ast_mutex_lock(&reglock);
338         for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) {
339                 old = freed->regions[idx];
340                 freed->regions[idx] = NULL;
341                 if (old) {
342                         region_data_check(old);
343                         free(old);
344                 }
345         }
346         freed->index = 0;
347         ast_mutex_unlock(&reglock);
348 }
349
350 /*!
351  * \internal
352  * \brief Delay freeing a region block.
353  *
354  * \param freed Already freed region blocks storage.
355  * \param reg Region block to be freed.
356  *
357  * \return Nothing
358  */
359 static void region_free(struct ast_freed_regions *freed, struct ast_region *reg)
360 {
361         struct ast_region *old;
362
363         region_data_wipe(reg);
364
365         ast_mutex_lock(&reglock);
366         old = freed->regions[freed->index];
367         freed->regions[freed->index] = reg;
368
369         ++freed->index;
370         if (ARRAY_LEN(freed->regions) <= freed->index) {
371                 freed->index = 0;
372         }
373         ast_mutex_unlock(&reglock);
374
375         if (old) {
376                 region_data_check(old);
377                 old->bt = ast_bt_destroy(old->bt);
378                 free(old);
379         }
380 }
381
382 /*!
383  * \internal
384  * \brief Remove a region from the active regions.
385  *
386  * \param ptr Region payload data pointer.
387  *
388  * \retval region on success.
389  * \retval NULL if not found.
390  */
391 static struct ast_region *region_remove(void *ptr)
392 {
393         int hash;
394         struct ast_region *reg;
395         struct ast_region *prev = NULL;
396
397         hash = HASH(ptr);
398
399         ast_mutex_lock(&reglock);
400         for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) {
401                 if (reg->data == ptr) {
402                         if (prev) {
403                                 AST_LIST_NEXT(prev, node) = AST_LIST_NEXT(reg, node);
404                         } else {
405                                 regions[hash] = AST_LIST_NEXT(reg, node);
406                         }
407                         break;
408                 }
409                 prev = reg;
410         }
411         ast_mutex_unlock(&reglock);
412
413         return reg;
414 }
415
416 /*!
417  * \internal
418  * \brief Check the fences of a region.
419  *
420  * \param reg Region block to check.
421  *
422  * \return Nothing
423  */
424 static void region_check_fences(struct ast_region *reg)
425 {
426         unsigned int *fence;
427
428         /*
429          * We use the bytes just preceeding reg->data and not reg->fence
430          * because there is likely to be padding between reg->fence and
431          * reg->data for reg->data alignment.
432          */
433         fence = (unsigned int *) (reg->data - sizeof(*fence));
434         if (*fence != FENCE_MAGIC) {
435                 astmm_log("WARNING: Low fence violation of %p allocated at %s %s() line %d\n",
436                         reg->data, reg->file, reg->func, reg->lineno);
437                 print_backtrace(reg->bt);
438                 my_do_crash();
439         }
440         fence = (unsigned int *) (reg->data + reg->len);
441         if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
442                 astmm_log("WARNING: High fence violation of %p allocated at %s %s() line %d\n",
443                         reg->data, reg->file, reg->func, reg->lineno);
444                 print_backtrace(reg->bt);
445                 my_do_crash();
446         }
447 }
448
449 /*!
450  * \internal
451  * \brief Check the fences of all regions currently allocated.
452  *
453  * \return Nothing
454  */
455 static void regions_check_all_fences(void)
456 {
457         int idx;
458         struct ast_region *reg;
459
460         ast_mutex_lock(&reglock);
461         for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
462                 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
463                         region_check_fences(reg);
464                 }
465         }
466         ast_mutex_unlock(&reglock);
467 }
468
469 void __ast_free(void *ptr, const char *file, int lineno, const char *func)
470 {
471         struct ast_region *reg;
472
473         if (!ptr) {
474                 return;
475         }
476
477         reg = region_remove(ptr);
478         if (reg) {
479                 region_check_fences(reg);
480
481                 if (reg->len <= MINNOWS_MAX_SIZE) {
482                         region_free(&minnows, reg);
483                 } else {
484                         region_free(&whales, reg);
485                 }
486         } else {
487                 /*
488                  * This memory region is not registered.  It could be because of
489                  * a double free or the memory block was not allocated by the
490                  * malloc debug code.
491                  */
492                 astmm_log("WARNING: Freeing unregistered memory %p by %s %s() line %d\n",
493                         ptr, file, func, lineno);
494                 my_do_crash();
495         }
496 }
497
498 void *__ast_repl_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
499 {
500         void *ptr;
501
502         ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 0);
503         if (ptr) {
504                 memset(ptr, 0, size * nmemb);
505         }
506
507         return ptr;
508 }
509
510 static void *__ast_repl_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
511 {
512         void *ptr;
513
514         ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 1);
515         if (ptr) {
516                 memset(ptr, 0, size * nmemb);
517         }
518
519         return ptr;
520 }
521
522 void *__ast_repl_malloc(size_t size, const char *file, int lineno, const char *func)
523 {
524         void *ptr;
525
526         ptr = __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func, 0);
527         if (ptr) {
528                 /* Make sure that the malloced memory is not zero. */
529                 memset(ptr, MALLOC_FILLER, size);
530         }
531
532         return ptr;
533 }
534
535 /*!
536  * \note reglock must be locked before calling.
537  */
538 static struct ast_region *region_find(void *ptr)
539 {
540         int hash;
541         struct ast_region *reg;
542
543         hash = HASH(ptr);
544         for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) {
545                 if (reg->data == ptr) {
546                         break;
547                 }
548         }
549
550         return reg;
551 }
552
553 void *__ast_repl_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
554 {
555         size_t len;
556         struct ast_region *found;
557         void *new_mem;
558
559         if (ptr) {
560                 ast_mutex_lock(&reglock);
561                 found = region_find(ptr);
562                 if (!found) {
563                         ast_mutex_unlock(&reglock);
564                         astmm_log("WARNING: Realloc of unregistered memory %p by %s %s() line %d\n",
565                                 ptr, file, func, lineno);
566                         my_do_crash();
567                         return NULL;
568                 }
569                 len = found->len;
570                 ast_mutex_unlock(&reglock);
571         } else {
572                 found = NULL;
573                 len = 0;
574         }
575
576         if (!size) {
577                 __ast_free(ptr, file, lineno, func);
578                 return NULL;
579         }
580
581         new_mem = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func, 0);
582         if (new_mem) {
583                 if (found) {
584                         /* Copy the old data to the new malloced memory. */
585                         if (size <= len) {
586                                 memcpy(new_mem, ptr, size);
587                         } else {
588                                 memcpy(new_mem, ptr, len);
589                                 /* Make sure that the added memory is not zero. */
590                                 memset(new_mem + len, MALLOC_FILLER, size - len);
591                         }
592                         __ast_free(ptr, file, lineno, func);
593                 } else {
594                         /* Make sure that the malloced memory is not zero. */
595                         memset(new_mem, MALLOC_FILLER, size);
596                 }
597         }
598
599         return new_mem;
600 }
601
602 char *__ast_repl_strdup(const char *s, const char *file, int lineno, const char *func)
603 {
604         size_t len;
605         void *ptr;
606
607         len = strlen(s) + 1;
608         if ((ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func, 0))) {
609                 strcpy(ptr, s);
610         }
611
612         return ptr;
613 }
614
615 char *__ast_repl_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
616 {
617         size_t len;
618         char *ptr;
619
620         len = strnlen(s, n);
621         if ((ptr = __ast_alloc_region(len + 1, FUNC_STRNDUP, file, lineno, func, 0))) {
622                 memcpy(ptr, s, len);
623                 ptr[len] = '\0';
624         }
625
626         return ptr;
627 }
628
629 int __ast_repl_asprintf(const char *file, int lineno, const char *func, char **strp, const char *fmt, ...)
630 {
631         int size;
632         va_list ap, ap2;
633         char s;
634         void *ptr;
635
636         va_start(ap, fmt);
637         va_copy(ap2, ap);
638         size = vsnprintf(&s, 1, fmt, ap2);
639         va_end(ap2);
640         ptr = __ast_alloc_region(size + 1, FUNC_ASPRINTF, file, lineno, func, 0);
641         if (!ptr) {
642                 /* As with stdlib *strp is undefined if allocation fails. */
643                 va_end(ap);
644                 return -1;
645         }
646         vsnprintf(ptr, size + 1, fmt, ap);
647         va_end(ap);
648         *strp = ptr;
649
650         return size;
651 }
652
653 int __ast_repl_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func)
654 {
655         int size;
656         va_list ap2;
657         char s;
658         void *ptr;
659
660         va_copy(ap2, ap);
661         size = vsnprintf(&s, 1, fmt, ap2);
662         va_end(ap2);
663         ptr = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func, 0);
664         if (!ptr) {
665                 /* As with stdlib *strp is undefined if allocation fails. */
666                 return -1;
667         }
668         vsnprintf(ptr, size + 1, fmt, ap);
669         *strp = ptr;
670
671         return size;
672 }
673
674 /*!
675  * \internal
676  * \brief Count the number of bytes in the specified freed region.
677  *
678  * \param freed Already freed region blocks storage.
679  *
680  * \note reglock must be locked before calling.
681  *
682  * \return Number of bytes in freed region.
683  */
684 static size_t freed_regions_size(struct ast_freed_regions *freed)
685 {
686         size_t total_len = 0;
687         int idx;
688         struct ast_region *old;
689
690         for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) {
691                 old = freed->regions[idx];
692                 if (old) {
693                         total_len += old->len;
694                 }
695         }
696
697         return total_len;
698 }
699
700 static char *handle_memory_atexit_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
701 {
702         switch (cmd) {
703         case CLI_INIT:
704                 e->command = "memory atexit list {on|off}";
705                 e->usage =
706                         "Usage: memory atexit list {on|off}\n"
707                         "       Enable dumping a list of still allocated memory segments at exit.\n";
708                 return NULL;
709         case CLI_GENERATE:
710                 return NULL;
711         }
712
713         if (a->argc != 4) {
714                 return CLI_SHOWUSAGE;
715         }
716
717         if (ast_true(a->argv[3])) {
718                 atexit_list = 1;
719         } else if (ast_false(a->argv[3])) {
720                 atexit_list = 0;
721         } else {
722                 return CLI_SHOWUSAGE;
723         }
724
725         ast_cli(a->fd, "The atexit list is: %s\n", atexit_list ? "On" : "Off");
726
727         return CLI_SUCCESS;
728 }
729
730 static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
731 {
732         char buf[80];
733
734         switch (cmd) {
735         case CLI_INIT:
736                 e->command = "memory atexit summary {off|byline|byfunc|byfile}";
737                 e->usage =
738                         "Usage: memory atexit summary {off|byline|byfunc|byfile}\n"
739                         "       Summary of still allocated memory segments at exit options.\n"
740                         "       off - Disable at exit summary.\n"
741                         "       byline - Enable at exit summary by file line number.\n"
742                         "       byfunc - Enable at exit summary by function name.\n"
743                         "       byfile - Enable at exit summary by file.\n"
744                         "\n"
745                         "       Note: byline, byfunc, and byfile are cumulative enables.\n";
746                 return NULL;
747         case CLI_GENERATE:
748                 return NULL;
749         }
750
751         if (a->argc != 4) {
752                 return CLI_SHOWUSAGE;
753         }
754
755         if (ast_false(a->argv[3])) {
756                 atexit_summary = SUMMARY_OFF;
757         } else if (!strcasecmp(a->argv[3], "byline")) {
758                 atexit_summary |= SUMMARY_BY_LINE;
759         } else if (!strcasecmp(a->argv[3], "byfunc")) {
760                 atexit_summary |= SUMMARY_BY_FUNC;
761         } else if (!strcasecmp(a->argv[3], "byfile")) {
762                 atexit_summary |= SUMMARY_BY_FILE;
763         } else {
764                 return CLI_SHOWUSAGE;
765         }
766
767         if (atexit_summary) {
768                 buf[0] = '\0';
769                 if (atexit_summary & SUMMARY_BY_LINE) {
770                         strcat(buf, "byline");
771                 }
772                 if (atexit_summary & SUMMARY_BY_FUNC) {
773                         if (buf[0]) {
774                                 strcat(buf, " | ");
775                         }
776                         strcat(buf, "byfunc");
777                 }
778                 if (atexit_summary & SUMMARY_BY_FILE) {
779                         if (buf[0]) {
780                                 strcat(buf, " | ");
781                         }
782                         strcat(buf, "byfile");
783                 }
784         } else {
785                 strcpy(buf, "Off");
786         }
787         ast_cli(a->fd, "The atexit summary is: %s\n", buf);
788
789         return CLI_SUCCESS;
790 }
791
792 /*!
793  * \internal
794  * \brief Common summary output at the end of the memory show commands.
795  *
796  * \param fd CLI output file descriptor.
797  * \param whales_len Accumulated size of free large allocations.
798  * \param minnows_len Accumulated size of free small allocations.
799  * \param total_len Accumulated size of all current allocations.
800  * \param selected_len Accumulated size of the selected allocations.
801  * \param cache_len Accumulated size of the allocations that are part of a cache.
802  * \param count Number of selected allocations.
803  *
804  * \return Nothing
805  */
806 static void print_memory_show_common_stats(int fd,
807         unsigned int whales_len,
808         unsigned int minnows_len,
809         unsigned int total_len,
810         unsigned int selected_len,
811         unsigned int cache_len,
812         unsigned int count)
813 {
814         if (cache_len) {
815                 ast_cli(fd, "%10u bytes allocated (%u in caches) in %u selected allocations\n\n",
816                         selected_len, cache_len, count);
817         } else {
818                 ast_cli(fd, "%10u bytes allocated in %u selected allocations\n\n",
819                         selected_len, count);
820         }
821
822         ast_cli(fd, "%10u bytes in all allocations\n", total_len);
823         ast_cli(fd, "%10u bytes in deferred free large allocations\n", whales_len);
824         ast_cli(fd, "%10u bytes in deferred free small allocations\n", minnows_len);
825         ast_cli(fd, "%10u bytes in deferred free allocations\n",
826                 whales_len + minnows_len);
827         ast_cli(fd, "%10u bytes in all allocations and deferred free allocations\n",
828                 total_len + whales_len + minnows_len);
829 }
830
831 static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
832 {
833         const char *fn = NULL;
834         struct ast_region *reg;
835         unsigned int idx;
836         unsigned int whales_len;
837         unsigned int minnows_len;
838         unsigned int total_len = 0;
839         unsigned int selected_len = 0;
840         unsigned int cache_len = 0;
841         unsigned int count = 0;
842
843         switch (cmd) {
844         case CLI_INIT:
845                 e->command = "memory show allocations";
846                 e->usage =
847                         "Usage: memory show allocations [<file>|anomalies]\n"
848                         "       Dumps a list of segments of allocated memory.\n"
849                         "       Defaults to listing all memory allocations.\n"
850                         "       <file> - Restricts output to memory allocated by the file.\n"
851                         "       anomalies - Only check for fence violations.\n";
852                 return NULL;
853         case CLI_GENERATE:
854                 return NULL;
855         }
856
857         if (a->argc == 4) {
858                 fn = a->argv[3];
859         } else if (a->argc != 3) {
860                 return CLI_SHOWUSAGE;
861         }
862
863         /* Look for historical misspelled option as well. */
864         if (fn && (!strcasecmp(fn, "anomalies") || !strcasecmp(fn, "anomolies"))) {
865                 regions_check_all_fences();
866                 ast_cli(a->fd, "Anomaly check complete.\n");
867                 return CLI_SUCCESS;
868         }
869
870         ast_mutex_lock(&reglock);
871         for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
872                 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
873                         total_len += reg->len;
874                         if (fn && strcasecmp(fn, reg->file)) {
875                                 continue;
876                         }
877
878                         region_check_fences(reg);
879
880                         ast_cli(a->fd, "%10u bytes allocated%s by %20s() line %5u of %s\n",
881                                 (unsigned int) reg->len, reg->cache ? " (cache)" : "",
882                                 reg->func, reg->lineno, reg->file);
883
884                         selected_len += reg->len;
885                         if (reg->cache) {
886                                 cache_len += reg->len;
887                         }
888                         ++count;
889                 }
890         }
891
892         whales_len = freed_regions_size(&whales);
893         minnows_len = freed_regions_size(&minnows);
894         ast_mutex_unlock(&reglock);
895
896         print_memory_show_common_stats(a->fd,
897                 whales_len, minnows_len, total_len,
898                 selected_len, cache_len, count);
899
900         return CLI_SUCCESS;
901 }
902
903 static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
904 {
905 #define my_max(a, b) ((a) >= (b) ? (a) : (b))
906
907         const char *fn = NULL;
908         int idx;
909         int cmp;
910         struct ast_region *reg;
911         unsigned int whales_len;
912         unsigned int minnows_len;
913         unsigned int total_len = 0;
914         unsigned int selected_len = 0;
915         unsigned int cache_len = 0;
916         unsigned int count = 0;
917         struct file_summary {
918                 struct file_summary *next;
919                 unsigned int len;
920                 unsigned int cache_len;
921                 unsigned int count;
922                 unsigned int lineno;
923                 char name[my_max(sizeof(reg->file), sizeof(reg->func))];
924         } *list = NULL, *cur, **prev;
925
926         switch (cmd) {
927         case CLI_INIT:
928                 e->command = "memory show summary";
929                 e->usage =
930                         "Usage: memory show summary [<file>]\n"
931                         "       Summarizes heap memory allocations by file, or optionally\n"
932                         "       by line if a file is specified.\n";
933                 return NULL;
934         case CLI_GENERATE:
935                 return NULL;
936         }
937
938         if (a->argc == 4) {
939                 fn = a->argv[3];
940         } else if (a->argc != 3) {
941                 return CLI_SHOWUSAGE;
942         }
943
944         ast_mutex_lock(&reglock);
945         for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
946                 for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
947                         total_len += reg->len;
948                         if (fn) {
949                                 if (strcasecmp(fn, reg->file)) {
950                                         continue;
951                                 }
952
953                                 /* Sort list by func/lineno.  Find existing or place to insert. */
954                                 for (prev = &list; (cur = *prev); prev = &cur->next) {
955                                         cmp = strcmp(cur->name, reg->func);
956                                         if (cmp < 0) {
957                                                 continue;
958                                         }
959                                         if (cmp > 0) {
960                                                 /* Insert before current */
961                                                 cur = NULL;
962                                                 break;
963                                         }
964                                         cmp = cur->lineno - reg->lineno;
965                                         if (cmp < 0) {
966                                                 continue;
967                                         }
968                                         if (cmp > 0) {
969                                                 /* Insert before current */
970                                                 cur = NULL;
971                                         }
972                                         break;
973                                 }
974                         } else {
975                                 /* Sort list by filename.  Find existing or place to insert. */
976                                 for (prev = &list; (cur = *prev); prev = &cur->next) {
977                                         cmp = strcmp(cur->name, reg->file);
978                                         if (cmp < 0) {
979                                                 continue;
980                                         }
981                                         if (cmp > 0) {
982                                                 /* Insert before current */
983                                                 cur = NULL;
984                                         }
985                                         break;
986                                 }
987                         }
988
989                         if (!cur) {
990                                 cur = ast_alloca(sizeof(*cur));
991                                 memset(cur, 0, sizeof(*cur));
992                                 cur->lineno = reg->lineno;
993                                 ast_copy_string(cur->name, fn ? reg->func : reg->file, sizeof(cur->name));
994
995                                 cur->next = *prev;
996                                 *prev = cur;
997                         }
998
999                         cur->len += reg->len;
1000                         if (reg->cache) {
1001                                 cur->cache_len += reg->len;
1002                         }
1003                         ++cur->count;
1004                 }
1005         }
1006
1007         whales_len = freed_regions_size(&whales);
1008         minnows_len = freed_regions_size(&minnows);
1009         ast_mutex_unlock(&reglock);
1010
1011         /* Dump the whole list */
1012         for (cur = list; cur; cur = cur->next) {
1013                 selected_len += cur->len;
1014                 cache_len += cur->cache_len;
1015                 count += cur->count;
1016                 if (cur->cache_len) {
1017                         if (fn) {
1018                                 ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations by %20s() line %5u of %s\n",
1019                                         cur->len, cur->cache_len, cur->count, cur->name, cur->lineno, fn);
1020                         } else {
1021                                 ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations in file %s\n",
1022                                         cur->len, cur->cache_len, cur->count, cur->name);
1023                         }
1024                 } else {
1025                         if (fn) {
1026                                 ast_cli(a->fd, "%10u bytes in %10u allocations by %20s() line %5u of %s\n",
1027                                         cur->len, cur->count, cur->name, cur->lineno, fn);
1028                         } else {
1029                                 ast_cli(a->fd, "%10u bytes in %10u allocations in file %s\n",
1030                                         cur->len, cur->count, cur->name);
1031                         }
1032                 }
1033         }
1034
1035         print_memory_show_common_stats(a->fd,
1036                 whales_len, minnows_len, total_len,
1037                 selected_len, cache_len, count);
1038
1039         return CLI_SUCCESS;
1040 }
1041
1042 static char *handle_memory_backtrace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1043 {
1044         switch (cmd) {
1045         case CLI_INIT:
1046                 e->command = "memory backtrace {on|off}";
1047                 e->usage =
1048                         "Usage: memory backtrace {on|off}\n"
1049                         "       Enable dumping an allocation backtrace with memory diagnostics.\n"
1050                         "       Note that saving the backtrace data for each allocation\n"
1051                         "       can be CPU intensive.\n";
1052                 return NULL;
1053         case CLI_GENERATE:
1054                 return NULL;
1055         }
1056
1057         if (a->argc != 3) {
1058                 return CLI_SHOWUSAGE;
1059         }
1060
1061         if (ast_true(a->argv[2])) {
1062                 backtrace_enabled = 1;
1063         } else if (ast_false(a->argv[2])) {
1064                 backtrace_enabled = 0;
1065         } else {
1066                 return CLI_SHOWUSAGE;
1067         }
1068
1069         ast_cli(a->fd, "The memory backtrace is: %s\n", backtrace_enabled ? "On" : "Off");
1070
1071         return CLI_SUCCESS;
1072 }
1073
1074 static struct ast_cli_entry cli_memory[] = {
1075         AST_CLI_DEFINE(handle_memory_atexit_list, "Enable memory allocations not freed at exit list."),
1076         AST_CLI_DEFINE(handle_memory_atexit_summary, "Enable memory allocations not freed at exit summary."),
1077         AST_CLI_DEFINE(handle_memory_show_allocations, "Display outstanding memory allocations"),
1078         AST_CLI_DEFINE(handle_memory_show_summary, "Summarize outstanding memory allocations"),
1079         AST_CLI_DEFINE(handle_memory_backtrace, "Enable dumping an allocation backtrace with memory diagnostics."),
1080 };
1081
1082 AST_LIST_HEAD_NOLOCK(region_list, ast_region);
1083
1084 /*!
1085  * \internal
1086  * \brief Convert the allocated regions hash table to a list.
1087  *
1088  * \param list Fill list with the allocated regions.
1089  *
1090  * \details
1091  * Take all allocated regions from the regions[] and put them
1092  * into the list.
1093  *
1094  * \note reglock must be locked before calling.
1095  *
1096  * \note This function is destructive to the regions[] lists.
1097  *
1098  * \return Length of list created.
1099  */
1100 static size_t mm_atexit_hash_list(struct region_list *list)
1101 {
1102         struct ast_region *reg;
1103         size_t total_length;
1104         int idx;
1105
1106         total_length = 0;
1107         for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
1108                 while ((reg = regions[idx])) {
1109                         regions[idx] = AST_LIST_NEXT(reg, node);
1110                         AST_LIST_NEXT(reg, node) = NULL;
1111                         AST_LIST_INSERT_HEAD(list, reg, node);
1112                         ++total_length;
1113                 }
1114         }
1115         return total_length;
1116 }
1117
1118 /*!
1119  * \internal
1120  * \brief Put the regions list into the allocated regions hash table.
1121  *
1122  * \param list List to put into the allocated regions hash table.
1123  *
1124  * \note reglock must be locked before calling.
1125  *
1126  * \return Nothing
1127  */
1128 static void mm_atexit_hash_restore(struct region_list *list)
1129 {
1130         struct ast_region *reg;
1131         int hash;
1132
1133         while ((reg = AST_LIST_REMOVE_HEAD(list, node))) {
1134                 hash = HASH(reg->data);
1135                 AST_LIST_NEXT(reg, node) = regions[hash];
1136                 regions[hash] = reg;
1137         }
1138 }
1139
1140 /*!
1141  * \internal
1142  * \brief Sort regions comparision.
1143  *
1144  * \param left Region to compare.
1145  * \param right Region to compare.
1146  *
1147  * \retval <0 if left < right
1148  * \retval =0 if left == right
1149  * \retval >0 if left > right
1150  */
1151 static int mm_atexit_cmp(struct ast_region *left, struct ast_region *right)
1152 {
1153         int cmp;
1154         ptrdiff_t cmp_ptr;
1155         ssize_t cmp_size;
1156
1157         /* Sort by filename. */
1158         cmp = strcmp(left->file, right->file);
1159         if (cmp) {
1160                 return cmp;
1161         }
1162
1163         /* Sort by line number. */
1164         cmp = left->lineno - right->lineno;
1165         if (cmp) {
1166                 return cmp;
1167         }
1168
1169         /* Sort by allocated size. */
1170         cmp_size = left->len - right->len;
1171         if (cmp_size) {
1172                 if (cmp_size < 0) {
1173                         return -1;
1174                 }
1175                 return 1;
1176         }
1177
1178         /* Sort by allocated pointers just because. */
1179         cmp_ptr = left->data - right->data;
1180         if (cmp_ptr) {
1181                 if (cmp_ptr < 0) {
1182                         return -1;
1183                 }
1184                 return 1;
1185         }
1186
1187         return 0;
1188 }
1189
1190 /*!
1191  * \internal
1192  * \brief Merge the given sorted sublists into sorted order onto the end of the list.
1193  *
1194  * \param list Merge sublists onto this list.
1195  * \param sub1 First sublist to merge.
1196  * \param sub2 Second sublist to merge.
1197  *
1198  * \return Nothing
1199  */
1200 static void mm_atexit_list_merge(struct region_list *list, struct region_list *sub1, struct region_list *sub2)
1201 {
1202         struct ast_region *reg;
1203
1204         for (;;) {
1205                 if (AST_LIST_EMPTY(sub1)) {
1206                         /* The remaining sublist goes onto the list. */
1207                         AST_LIST_APPEND_LIST(list, sub2, node);
1208                         break;
1209                 }
1210                 if (AST_LIST_EMPTY(sub2)) {
1211                         /* The remaining sublist goes onto the list. */
1212                         AST_LIST_APPEND_LIST(list, sub1, node);
1213                         break;
1214                 }
1215
1216                 if (mm_atexit_cmp(AST_LIST_FIRST(sub1), AST_LIST_FIRST(sub2)) <= 0) {
1217                         reg = AST_LIST_REMOVE_HEAD(sub1, node);
1218                 } else {
1219                         reg = AST_LIST_REMOVE_HEAD(sub2, node);
1220                 }
1221                 AST_LIST_INSERT_TAIL(list, reg, node);
1222         }
1223 }
1224
1225 /*!
1226  * \internal
1227  * \brief Take sublists off of the given list.
1228  *
1229  * \param list Source list to remove sublists from the beginning of list.
1230  * \param sub Array of sublists to fill. (Lists are empty on entry.)
1231  * \param num_lists Number of lists to remove from the source list.
1232  * \param size Size of the sublists to remove.
1233  * \param remaining Remaining number of elements on the source list.
1234  *
1235  * \return Nothing
1236  */
1237 static void mm_atexit_list_split(struct region_list *list, struct region_list sub[], size_t num_lists, size_t size, size_t *remaining)
1238 {
1239         int idx;
1240
1241         for (idx = 0; idx < num_lists; ++idx) {
1242                 size_t count;
1243
1244                 if (*remaining < size) {
1245                         /* The remaining source list goes onto the sublist. */
1246                         AST_LIST_APPEND_LIST(&sub[idx], list, node);
1247                         *remaining = 0;
1248                         break;
1249                 }
1250
1251                 /* Take a sublist off the beginning of the source list. */
1252                 *remaining -= size;
1253                 for (count = size; count--;) {
1254                         struct ast_region *reg;
1255
1256                         reg = AST_LIST_REMOVE_HEAD(list, node);
1257                         AST_LIST_INSERT_TAIL(&sub[idx], reg, node);
1258                 }
1259         }
1260 }
1261
1262 /*!
1263  * \internal
1264  * \brief Sort the regions list using mergesort.
1265  *
1266  * \param list Allocated regions list to sort.
1267  * \param length Length of the list.
1268  *
1269  * \return Nothing
1270  */
1271 static void mm_atexit_list_sort(struct region_list *list, size_t length)
1272 {
1273         /*! Semi-sorted merged list. */
1274         struct region_list merged = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1275         /*! Sublists to merge. (Can only merge two sublists at this time.) */
1276         struct region_list sub[2] = {
1277                 AST_LIST_HEAD_NOLOCK_INIT_VALUE,
1278                 AST_LIST_HEAD_NOLOCK_INIT_VALUE
1279         };
1280         /*! Sublist size. */
1281         size_t size = 1;
1282         /*! Remaining elements in the list. */
1283         size_t remaining;
1284         /*! Number of sublist merge passes to process the list. */
1285         int passes;
1286
1287         for (;;) {
1288                 remaining = length;
1289
1290                 passes = 0;
1291                 while (!AST_LIST_EMPTY(list)) {
1292                         mm_atexit_list_split(list, sub, ARRAY_LEN(sub), size, &remaining);
1293                         mm_atexit_list_merge(&merged, &sub[0], &sub[1]);
1294                         ++passes;
1295                 }
1296                 AST_LIST_APPEND_LIST(list, &merged, node);
1297                 if (passes <= 1) {
1298                         /* The list is now sorted. */
1299                         break;
1300                 }
1301
1302                 /* Double the sublist size to remove for next round. */
1303                 size <<= 1;
1304         }
1305 }
1306
1307 /*!
1308  * \internal
1309  * \brief List all regions currently allocated.
1310  *
1311  * \param alloced regions list.
1312  *
1313  * \return Nothing
1314  */
1315 static void mm_atexit_regions_list(struct region_list *alloced)
1316 {
1317         struct ast_region *reg;
1318
1319         AST_LIST_TRAVERSE(alloced, reg, node) {
1320                 astmm_log("%s %s() line %u: %u bytes%s at %p\n",
1321                         reg->file, reg->func, reg->lineno,
1322                         (unsigned int) reg->len, reg->cache ? " (cache)" : "", reg->data);
1323         }
1324 }
1325
1326 /*!
1327  * \internal
1328  * \brief Summarize all regions currently allocated.
1329  *
1330  * \param alloced Sorted regions list.
1331  *
1332  * \return Nothing
1333  */
1334 static void mm_atexit_regions_summary(struct region_list *alloced)
1335 {
1336         struct ast_region *reg;
1337         struct ast_region *next;
1338         struct {
1339                 unsigned int count;
1340                 unsigned int len;
1341                 unsigned int cache_len;
1342         } by_line, by_func, by_file, total;
1343
1344         by_line.count = 0;
1345         by_line.len = 0;
1346         by_line.cache_len = 0;
1347
1348         by_func.count = 0;
1349         by_func.len = 0;
1350         by_func.cache_len = 0;
1351
1352         by_file.count = 0;
1353         by_file.len = 0;
1354         by_file.cache_len = 0;
1355
1356         total.count = 0;
1357         total.len = 0;
1358         total.cache_len = 0;
1359
1360         AST_LIST_TRAVERSE(alloced, reg, node) {
1361                 next = AST_LIST_NEXT(reg, node);
1362
1363                 ++by_line.count;
1364                 by_line.len += reg->len;
1365                 if (reg->cache) {
1366                         by_line.cache_len += reg->len;
1367                 }
1368                 if (next && !strcmp(reg->file, next->file) && reg->lineno == next->lineno) {
1369                         continue;
1370                 }
1371                 if (atexit_summary & SUMMARY_BY_LINE) {
1372                         if (by_line.cache_len) {
1373                                 astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s() line %u\n",
1374                                         by_line.len, by_line.cache_len, by_line.count, reg->file, reg->func, reg->lineno);
1375                         } else {
1376                                 astmm_log("%10u bytes in %5u allocations. %s %s() line %u\n",
1377                                         by_line.len, by_line.count, reg->file, reg->func, reg->lineno);
1378                         }
1379                 }
1380
1381                 by_func.count += by_line.count;
1382                 by_func.len += by_line.len;
1383                 by_func.cache_len += by_line.cache_len;
1384                 by_line.count = 0;
1385                 by_line.len = 0;
1386                 by_line.cache_len = 0;
1387                 if (next && !strcmp(reg->file, next->file) && !strcmp(reg->func, next->func)) {
1388                         continue;
1389                 }
1390                 if (atexit_summary & SUMMARY_BY_FUNC) {
1391                         if (by_func.cache_len) {
1392                                 astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s()\n",
1393                                         by_func.len, by_func.cache_len, by_func.count, reg->file, reg->func);
1394                         } else {
1395                                 astmm_log("%10u bytes in %5u allocations. %s %s()\n",
1396                                         by_func.len, by_func.count, reg->file, reg->func);
1397                         }
1398                 }
1399
1400                 by_file.count += by_func.count;
1401                 by_file.len += by_func.len;
1402                 by_file.cache_len += by_func.cache_len;
1403                 by_func.count = 0;
1404                 by_func.len = 0;
1405                 by_func.cache_len = 0;
1406                 if (next && !strcmp(reg->file, next->file)) {
1407                         continue;
1408                 }
1409                 if (atexit_summary & SUMMARY_BY_FILE) {
1410                         if (by_file.cache_len) {
1411                                 astmm_log("%10u bytes (%u in caches) in %u allocations. %s\n",
1412                                         by_file.len, by_file.cache_len, by_file.count, reg->file);
1413                         } else {
1414                                 astmm_log("%10u bytes in %5u allocations. %s\n",
1415                                         by_file.len, by_file.count, reg->file);
1416                         }
1417                 }
1418
1419                 total.count += by_file.count;
1420                 total.len += by_file.len;
1421                 total.cache_len += by_file.cache_len;
1422                 by_file.count = 0;
1423                 by_file.len = 0;
1424                 by_file.cache_len = 0;
1425         }
1426
1427         if (total.cache_len) {
1428                 astmm_log("%u bytes (%u in caches) in %u allocations.\n",
1429                         total.len, total.cache_len, total.count);
1430         } else {
1431                 astmm_log("%u bytes in %u allocations.\n", total.len, total.count);
1432         }
1433 }
1434
1435 /*!
1436  * \internal
1437  * \brief Dump the memory allocations atexit.
1438  *
1439  * \note reglock must be locked before calling.
1440  *
1441  * \return Nothing
1442  */
1443 static void mm_atexit_dump(void)
1444 {
1445         struct region_list alloced_atexit = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1446         size_t length;
1447
1448         length = mm_atexit_hash_list(&alloced_atexit);
1449         if (!length) {
1450                 /* Wow!  This is amazing! */
1451                 astmm_log("Exiting with all memory freed.\n");
1452                 return;
1453         }
1454
1455         mm_atexit_list_sort(&alloced_atexit, length);
1456
1457         astmm_log("Exiting with the following memory not freed:\n");
1458         if (atexit_list) {
1459                 mm_atexit_regions_list(&alloced_atexit);
1460         }
1461         if (atexit_summary) {
1462                 mm_atexit_regions_summary(&alloced_atexit);
1463         }
1464
1465         /*
1466          * Put the alloced list back into regions[].
1467          *
1468          * We have do this because we can get called before all other
1469          * threads have terminated.
1470          */
1471         mm_atexit_hash_restore(&alloced_atexit);
1472 }
1473
1474 /*!
1475  * \internal
1476  * \return Nothing
1477  */
1478 static void mm_atexit_final(void)
1479 {
1480         FILE *log;
1481
1482         /* Only wait if we want atexit allocation dumps. */
1483         if (atexit_list || atexit_summary) {
1484                 fprintf(stderr, "Waiting 10 seconds to let other threads die.\n");
1485                 sleep(10);
1486         }
1487
1488         regions_check_all_fences();
1489
1490         /* Flush all delayed memory free circular arrays. */
1491         freed_regions_flush(&whales);
1492         freed_regions_flush(&minnows);
1493
1494         /* Peform atexit allocation dumps. */
1495         if (atexit_list || atexit_summary) {
1496                 ast_mutex_lock(&reglock);
1497                 mm_atexit_dump();
1498                 ast_mutex_unlock(&reglock);
1499         }
1500
1501         /* Close the log file. */
1502         log = mmlog;
1503         mmlog = NULL;
1504         if (log) {
1505                 fclose(log);
1506         }
1507 }
1508
1509 void load_astmm_phase_1(void)
1510 {
1511         atexit(mm_atexit_final);
1512 }
1513
1514 /*!
1515  * \internal
1516  * \return Nothing
1517  */
1518 static void mm_atexit_ast(void)
1519 {
1520         ast_cli_unregister_multiple(cli_memory, ARRAY_LEN(cli_memory));
1521 }
1522
1523 void load_astmm_phase_2(void)
1524 {
1525         char filename[PATH_MAX];
1526
1527         ast_cli_register_multiple(cli_memory, ARRAY_LEN(cli_memory));
1528
1529         snprintf(filename, sizeof(filename), "%s/mmlog", ast_config_AST_LOG_DIR);
1530
1531         ast_verb(1, "Asterisk Malloc Debugger Started (see %s))\n", filename);
1532
1533         mmlog = fopen(filename, "a+");
1534         if (mmlog) {
1535                 fprintf(mmlog, "%ld - New session\n", (long) time(NULL));
1536                 fflush(mmlog);
1537         } else {
1538                 ast_log(LOG_ERROR, "Could not open malloc debug log file: %s\n", filename);
1539         }
1540
1541         ast_register_cleanup(mm_atexit_ast);
1542 }
1543
1544 #else   /* !defined(__AST_DEBUG_MALLOC) */
1545
1546 void load_astmm_phase_1(void)
1547 {
1548 }
1549
1550 void load_astmm_phase_2(void)
1551 {
1552 }
1553
1554 void *__ast_repl_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
1555 {
1556         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
1557
1558         return calloc(nmemb, size);
1559 }
1560
1561 static void *__ast_repl_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
1562 {
1563         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
1564
1565         return calloc(nmemb, size);
1566 }
1567
1568 void *__ast_repl_malloc(size_t size, const char *file, int lineno, const char *func)
1569 {
1570         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
1571
1572         return malloc(size);
1573 }
1574
1575 void __ast_free(void *ptr, const char *file, int lineno, const char *func)
1576 {
1577         free(ptr);
1578 }
1579
1580 void *__ast_repl_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
1581 {
1582         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
1583
1584         return realloc(ptr, size);
1585 }
1586
1587 char *__ast_repl_strdup(const char *s, const char *file, int lineno, const char *func)
1588 {
1589         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
1590
1591         return strdup(s);
1592 }
1593
1594 char *__ast_repl_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
1595 {
1596         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL);
1597
1598         return strndup(s, n);
1599 }
1600
1601 int __ast_repl_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...)
1602 {
1603         int res;
1604         va_list ap;
1605
1606         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1);
1607
1608         va_start(ap, format);
1609         res = vasprintf(strp, format, ap);
1610         va_end(ap);
1611
1612         return res;
1613 }
1614
1615 int __ast_repl_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func)
1616 {
1617         DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1);
1618
1619         return vasprintf(strp, format, ap);
1620 }
1621
1622 #endif  /* defined(__AST_DEBUG_MALLOC) */
1623
1624 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
1625 {
1626         void *p;
1627
1628         p = __ast_repl_calloc(nmemb, size, file, lineno, func);
1629         if (!p) {
1630                 MALLOC_FAILURE_MSG;
1631         }
1632
1633         return p;
1634 }
1635
1636 void *__ast_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
1637 {
1638         void *p;
1639
1640         p = __ast_repl_calloc_cache(nmemb, size, file, lineno, func);
1641         if (!p) {
1642                 MALLOC_FAILURE_MSG;
1643         }
1644
1645         return p;
1646
1647 }
1648
1649 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
1650 {
1651         void *p;
1652
1653         p = __ast_repl_malloc(size, file, lineno, func);
1654         if (!p) {
1655                 MALLOC_FAILURE_MSG;
1656         }
1657
1658         return p;
1659 }
1660
1661 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
1662 {
1663         void *newp;
1664
1665         newp = __ast_repl_realloc(ptr, size, file, lineno, func);
1666         if (!newp) {
1667                 MALLOC_FAILURE_MSG;
1668         }
1669
1670         return newp;
1671 }
1672
1673 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
1674 {
1675         char *newstr = NULL;
1676
1677         if (s) {
1678                 newstr = __ast_repl_strdup(s, file, lineno, func);
1679                 if (!newstr) {
1680                         MALLOC_FAILURE_MSG;
1681                 }
1682         }
1683
1684         return newstr;
1685 }
1686
1687 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
1688 {
1689         char *newstr = NULL;
1690
1691         if (s) {
1692                 newstr = __ast_repl_strndup(s, n, file, lineno, func);
1693                 if (!newstr) {
1694                         MALLOC_FAILURE_MSG;
1695                 }
1696         }
1697
1698         return newstr;
1699 }
1700
1701 int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...)
1702 {
1703         int res;
1704         va_list ap;
1705
1706         va_start(ap, format);
1707         res = __ast_repl_vasprintf(strp, format, ap, file, lineno, func);
1708         if (res < 0) {
1709                 /*
1710                  * *strp is undefined so set to NULL to ensure it is
1711                  * initialized to something useful.
1712                  */
1713                 *strp = NULL;
1714
1715                 MALLOC_FAILURE_MSG;
1716         }
1717         va_end(ap);
1718
1719         return res;
1720 }
1721
1722 int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func)
1723 {
1724         int res;
1725
1726         res = __ast_repl_vasprintf(strp, format, ap, file, lineno, func);
1727         if (res < 0) {
1728                 /*
1729                  * *strp is undefined so set to NULL to ensure it is
1730                  * initialized to something useful.
1731                  */
1732                 *strp = NULL;
1733
1734                 MALLOC_FAILURE_MSG;
1735         }
1736
1737         return res;
1738 }
1739
1740 void *ast_std_malloc(size_t size)
1741 {
1742         return malloc(size);
1743 }
1744
1745 void *ast_std_calloc(size_t nmemb, size_t size)
1746 {
1747         return calloc(nmemb, size);
1748 }
1749
1750 void *ast_std_realloc(void *ptr, size_t size)
1751 {
1752         return realloc(ptr, size);
1753 }
1754
1755 void ast_std_free(void *ptr)
1756 {
1757         free(ptr);
1758 }
1759
1760 void ast_free_ptr(void *ptr)
1761 {
1762         ast_free(ptr);
1763 }