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