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