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