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