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