| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  |  * Copyright (C) 1999 - 2012, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-03-23 05:56:32 +00:00
										 |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief Memory Management | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Mark Spencer <markster@digium.com> | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  |  * \author Richard Mudgett <rmudgett@digium.com> | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-15 16:20:16 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>core</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 09:58:52 -04:00
										 |  |  | #define ASTMM_LIBC ASTMM_IGNORE
 | 
					
						
							| 
									
										
										
										
											2005-06-06 20:27:51 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 00:54:11 -04:00
										 |  |  | #include "asterisk/_private.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | #include "asterisk/logger.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief DEBUG_CHAOS returns failure randomly | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * DEBUG_CHAOS_RETURN(failure); can be used to fake | 
					
						
							|  |  |  |  * failure of functions such as memory allocation, | 
					
						
							|  |  |  |  * for the purposes of testing failure handling. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifdef DEBUG_CHAOS
 | 
					
						
							|  |  |  | #ifndef DEBUG_CHAOS_ALLOC_CHANCE
 | 
					
						
							|  |  |  | #define DEBUG_CHAOS_ALLOC_CHANCE 100000
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | /* Could #define DEBUG_CHAOS_ENABLE ast_fully_booted */ | 
					
						
							|  |  |  | #ifndef DEBUG_CHAOS_ENABLE
 | 
					
						
							|  |  |  | #define DEBUG_CHAOS_ENABLE 1
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #define DEBUG_CHAOS_RETURN(CHANCE, FAILURE) \
 | 
					
						
							|  |  |  | 	do { \ | 
					
						
							|  |  |  | 		if ((DEBUG_CHAOS_ENABLE) && (ast_random() % CHANCE == 0)) { \ | 
					
						
							|  |  |  | 			return FAILURE; \ | 
					
						
							|  |  |  | 		} \ | 
					
						
							|  |  |  | 	} while (0) | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define DEBUG_CHAOS_RETURN(c,f)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(STANDALONE) || defined(STANDALONE2)
 | 
					
						
							|  |  |  | #define ast_log_safe ast_log
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 00:54:11 -04:00
										 |  |  | #if defined(MALLOC_DEBUG) && !defined(STANDALONE) && !defined(STANDALONE2)
 | 
					
						
							|  |  |  | #define __AST_DEBUG_MALLOC
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | #define MALLOC_FAILURE_MSG \
 | 
					
						
							|  |  |  | 	ast_log_safe(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | #if defined(__AST_DEBUG_MALLOC)
 | 
					
						
							| 
									
										
										
										
											2008-09-27 15:52:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-21 01:35:30 +00:00
										 |  |  | #include "asterisk/paths.h"	/* use ast_config_AST_LOG_DIR */
 | 
					
						
							| 
									
										
										
										
											2008-07-11 14:16:15 +00:00
										 |  |  | #include <stddef.h>
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include <time.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/cli.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							| 
									
										
										
										
											2005-08-23 15:08:55 +00:00
										 |  |  | #include "asterisk/strings.h"
 | 
					
						
							| 
									
										
										
										
											2006-03-20 02:00:30 +00:00
										 |  |  | #include "asterisk/unaligned.h"
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | #include "asterisk/backtrace.h"
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * The larger the number the faster memory can be freed. | 
					
						
							|  |  |  |  * However, more memory then is used for the regions[] hash | 
					
						
							|  |  |  |  * table. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define SOME_PRIME 1567
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-15 01:48:54 +00:00
										 |  |  | enum func_type { | 
					
						
							|  |  |  | 	FUNC_CALLOC = 1, | 
					
						
							|  |  |  | 	FUNC_MALLOC, | 
					
						
							|  |  |  | 	FUNC_REALLOC, | 
					
						
							|  |  |  | 	FUNC_STRDUP, | 
					
						
							|  |  |  | 	FUNC_STRNDUP, | 
					
						
							|  |  |  | 	FUNC_VASPRINTF, | 
					
						
							|  |  |  | 	FUNC_ASPRINTF | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-09 23:29:44 +00:00
										 |  |  | #define FENCE_MAGIC		0xfeedbabe	/*!< Allocated memory high/low fence overwrite check. */
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | #define FREED_MAGIC		0xdeaddead	/*!< Freed memory wipe filler. */
 | 
					
						
							|  |  |  | #define MALLOC_FILLER	0x55		/*!< Malloced memory filler.  Must not be zero. */
 | 
					
						
							| 
									
										
										
										
											2005-09-29 04:34:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-06 00:01:32 +00:00
										 |  |  | static FILE *mmlog; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | struct ast_region { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	AST_LIST_ENTRY(ast_region) node; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	struct ast_bt *bt; | 
					
						
							| 
									
										
										
										
											2008-07-11 14:16:15 +00:00
										 |  |  | 	size_t len; | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	unsigned int cache;		/* region was allocated as part of a cache pool */ | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	unsigned int lineno; | 
					
						
							| 
									
										
										
										
											2006-02-15 01:48:54 +00:00
										 |  |  | 	enum func_type which; | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	char file[64]; | 
					
						
							|  |  |  | 	char func[40]; | 
					
						
							|  |  |  | 	/*!
 | 
					
						
							|  |  |  | 	 * \brief Lower guard fence. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * \note Must be right before data[]. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * \note Padding between fence and data[] is irrelevent because | 
					
						
							|  |  |  | 	 * data[] is used to fill in the lower fence check value and not | 
					
						
							|  |  |  | 	 * the fence member.  The fence member is to ensure that there | 
					
						
							|  |  |  | 	 * is space reserved for the fence check value. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-09-29 04:34:11 +00:00
										 |  |  | 	unsigned int fence; | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	/*!
 | 
					
						
							|  |  |  | 	 * \brief Location of the requested malloc block to return. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * \note Must have the same alignment that malloc returns. | 
					
						
							|  |  |  | 	 * i.e., It is suitably aligned for any kind of varible. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	unsigned char data[0] __attribute__((aligned)); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! Hash table of lists of active allocated memory regions. */ | 
					
						
							|  |  |  | static struct ast_region *regions[SOME_PRIME]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! Number of freed regions to keep around to delay actually freeing them. */ | 
					
						
							|  |  |  | #define FREED_MAX_COUNT		1500
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*! Maximum size of a minnow block */ | 
					
						
							|  |  |  | #define MINNOWS_MAX_SIZE	50
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ast_freed_regions { | 
					
						
							|  |  |  | 	/*! Memory regions that have been freed. */ | 
					
						
							|  |  |  | 	struct ast_region *regions[FREED_MAX_COUNT]; | 
					
						
							|  |  |  | 	/*! Next index into freed regions[] to use. */ | 
					
						
							|  |  |  | 	int index; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! Large memory blocks that have been freed. */ | 
					
						
							|  |  |  | static struct ast_freed_regions whales; | 
					
						
							|  |  |  | /*! Small memory blocks that have been freed. */ | 
					
						
							|  |  |  | static struct ast_freed_regions minnows; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | enum summary_opts { | 
					
						
							|  |  |  | 	/*! No summary at exit. */ | 
					
						
							|  |  |  | 	SUMMARY_OFF, | 
					
						
							|  |  |  | 	/*! Bit set if summary by line at exit. */ | 
					
						
							|  |  |  | 	SUMMARY_BY_LINE = (1 << 0), | 
					
						
							|  |  |  | 	/*! Bit set if summary by function at exit. */ | 
					
						
							|  |  |  | 	SUMMARY_BY_FUNC = (1 << 1), | 
					
						
							|  |  |  | 	/*! Bit set if summary by file at exit. */ | 
					
						
							|  |  |  | 	SUMMARY_BY_FILE = (1 << 2), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! Summary options of unfreed regions at exit. */ | 
					
						
							|  |  |  | static enum summary_opts atexit_summary; | 
					
						
							|  |  |  | /*! Nonzero if the unfreed regions are listed at exit. */ | 
					
						
							|  |  |  | static int atexit_list; | 
					
						
							| 
									
										
										
										
											2013-08-27 18:52:23 +00:00
										 |  |  | /*! Nonzero if the memory allocation backtrace is enabled. */ | 
					
						
							|  |  |  | static int backtrace_enabled; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | #define HASH(a)		(((unsigned long)(a)) % ARRAY_LEN(regions))
 | 
					
						
							| 
									
										
										
										
											2007-08-03 19:41:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*! Tracking this mutex will cause infinite recursion, as the mutex tracking
 | 
					
						
							|  |  |  |  *  code allocates memory */ | 
					
						
							|  |  |  | AST_MUTEX_DEFINE_STATIC_NOTRACKING(reglock); | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | #define astmm_log(...)                               \
 | 
					
						
							|  |  |  | 	do {                                         \ | 
					
						
							|  |  |  | 		fprintf(stderr, __VA_ARGS__);        \ | 
					
						
							|  |  |  | 		if (mmlog) {                         \ | 
					
						
							|  |  |  | 			fprintf(mmlog, __VA_ARGS__); \ | 
					
						
							|  |  |  | 			fflush(mmlog);               \ | 
					
						
							|  |  |  | 		}                                    \ | 
					
						
							|  |  |  | 	} while (0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | static void print_backtrace(struct ast_bt *bt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	struct ast_vector_string *strings; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!bt) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) { | 
					
						
							|  |  |  | 		astmm_log("Memory allocation backtrace:\n"); | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		for (i = 3; i < AST_VECTOR_SIZE(strings) - 2; i++) { | 
					
						
							|  |  |  | 			astmm_log("#%d: %s\n", i - 3, AST_VECTOR_GET(strings, i)); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		ast_bt_free_symbols(strings); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note If DO_CRASH is not defined then the function returns. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void my_do_crash(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Give the logger a chance to get the message out, just in case | 
					
						
							|  |  |  | 	 * we abort(), or Asterisk crashes due to whatever problem just | 
					
						
							|  |  |  | 	 * happened. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	usleep(1); | 
					
						
							|  |  |  | 	ast_do_crash(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void *__ast_alloc_region(size_t size, const enum func_type which, const char *file, int lineno, const char *func, unsigned int cache) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							| 
									
										
										
										
											2005-09-29 04:34:11 +00:00
										 |  |  | 	unsigned int *fence; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	int hash; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	if (!(reg = malloc(size + sizeof(*reg) + sizeof(*fence)))) { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		astmm_log("Memory Allocation Failure - '%d' bytes at %s %s() line %d\n", | 
					
						
							|  |  |  | 			(int) size, file, func, lineno); | 
					
						
							| 
									
										
										
										
											2008-11-19 00:59:48 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reg->len = size; | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 	reg->cache = cache; | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	reg->lineno = lineno; | 
					
						
							|  |  |  | 	reg->which = which; | 
					
						
							| 
									
										
										
										
											2013-08-27 18:52:23 +00:00
										 |  |  | 	reg->bt = backtrace_enabled ? ast_bt_create() : NULL; | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	ast_copy_string(reg->file, file, sizeof(reg->file)); | 
					
						
							|  |  |  | 	ast_copy_string(reg->func, func, sizeof(reg->func)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Init lower fence. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * We use the bytes just preceeding reg->data and not reg->fence | 
					
						
							|  |  |  | 	 * because there is likely to be padding between reg->fence and | 
					
						
							|  |  |  | 	 * reg->data for reg->data alignment. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	fence = (unsigned int *) (reg->data - sizeof(*fence)); | 
					
						
							|  |  |  | 	*fence = FENCE_MAGIC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Init higher fence. */ | 
					
						
							|  |  |  | 	fence = (unsigned int *) (reg->data + reg->len); | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	put_unaligned_uint32(fence, FENCE_MAGIC); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	hash = HASH(reg->data); | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	ast_mutex_lock(®lock); | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	AST_LIST_NEXT(reg, node) = regions[hash]; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	regions[hash] = reg; | 
					
						
							| 
									
										
										
										
											2003-08-13 15:25:16 +00:00
										 |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	return reg->data; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Wipe the region payload data with a known value. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param reg Region block to be wiped. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void region_data_wipe(struct ast_region *reg) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	void *end; | 
					
						
							|  |  |  | 	unsigned int *pos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Wipe the lower fence, the payload, and whatever amount of the | 
					
						
							|  |  |  | 	 * higher fence that falls into alignment with the payload. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	end = reg->data + reg->len; | 
					
						
							|  |  |  | 	for (pos = ®->fence; (void *) pos <= end; ++pos) { | 
					
						
							|  |  |  | 		*pos = FREED_MAGIC; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Check the region payload data for memory corruption. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param reg Region block to be checked. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void region_data_check(struct ast_region *reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *end; | 
					
						
							|  |  |  | 	unsigned int *pos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Check the lower fence, the payload, and whatever amount of | 
					
						
							|  |  |  | 	 * the higher fence that falls into alignment with the payload. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	end = reg->data + reg->len; | 
					
						
							|  |  |  | 	for (pos = ®->fence; (void *) pos <= end; ++pos) { | 
					
						
							|  |  |  | 		if (*pos != FREED_MAGIC) { | 
					
						
							|  |  |  | 			astmm_log("WARNING: Memory corrupted after free of %p allocated at %s %s() line %d\n", | 
					
						
							|  |  |  | 				reg->data, reg->file, reg->func, reg->lineno); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 			print_backtrace(reg->bt); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 			my_do_crash(); | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Flush the circular array of freed regions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param freed Already freed region blocks storage. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void freed_regions_flush(struct ast_freed_regions *freed) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 	struct ast_region *old; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(®lock); | 
					
						
							|  |  |  | 	for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) { | 
					
						
							|  |  |  | 		old = freed->regions[idx]; | 
					
						
							|  |  |  | 		freed->regions[idx] = NULL; | 
					
						
							|  |  |  | 		if (old) { | 
					
						
							|  |  |  | 			region_data_check(old); | 
					
						
							|  |  |  | 			free(old); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	freed->index = 0; | 
					
						
							| 
									
										
										
										
											2003-08-13 15:25:16 +00:00
										 |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Delay freeing a region block. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param freed Already freed region blocks storage. | 
					
						
							|  |  |  |  * \param reg Region block to be freed. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void region_free(struct ast_freed_regions *freed, struct ast_region *reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *old; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	region_data_wipe(reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(®lock); | 
					
						
							|  |  |  | 	old = freed->regions[freed->index]; | 
					
						
							|  |  |  | 	freed->regions[freed->index] = reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	++freed->index; | 
					
						
							|  |  |  | 	if (ARRAY_LEN(freed->regions) <= freed->index) { | 
					
						
							|  |  |  | 		freed->index = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (old) { | 
					
						
							|  |  |  | 		region_data_check(old); | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 		old->bt = ast_bt_destroy(old->bt); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		free(old); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Remove a region from the active regions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param ptr Region payload data pointer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval region on success. | 
					
						
							|  |  |  |  * \retval NULL if not found. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct ast_region *region_remove(void *ptr) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-09-17 20:25:40 +00:00
										 |  |  | 	int hash; | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 	struct ast_region *prev = NULL; | 
					
						
							| 
									
										
										
										
											2008-09-17 20:25:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hash = HASH(ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-13 15:25:16 +00:00
										 |  |  | 	ast_mutex_lock(®lock); | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) { | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 		if (reg->data == ptr) { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 			if (prev) { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 				AST_LIST_NEXT(prev, node) = AST_LIST_NEXT(reg, node); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 				regions[hash] = AST_LIST_NEXT(reg, node); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		prev = reg; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-08-13 15:25:16 +00:00
										 |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	return reg; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Check the fences of a region. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param reg Region block to check. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void region_check_fences(struct ast_region *reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int *fence; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * We use the bytes just preceeding reg->data and not reg->fence | 
					
						
							|  |  |  | 	 * because there is likely to be padding between reg->fence and | 
					
						
							|  |  |  | 	 * reg->data for reg->data alignment. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	fence = (unsigned int *) (reg->data - sizeof(*fence)); | 
					
						
							|  |  |  | 	if (*fence != FENCE_MAGIC) { | 
					
						
							|  |  |  | 		astmm_log("WARNING: Low fence violation of %p allocated at %s %s() line %d\n", | 
					
						
							|  |  |  | 			reg->data, reg->file, reg->func, reg->lineno); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		print_backtrace(reg->bt); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		my_do_crash(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fence = (unsigned int *) (reg->data + reg->len); | 
					
						
							|  |  |  | 	if (get_unaligned_uint32(fence) != FENCE_MAGIC) { | 
					
						
							|  |  |  | 		astmm_log("WARNING: High fence violation of %p allocated at %s %s() line %d\n", | 
					
						
							|  |  |  | 			reg->data, reg->file, reg->func, reg->lineno); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		print_backtrace(reg->bt); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		my_do_crash(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Check the fences of all regions currently allocated. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void regions_check_all_fences(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(®lock); | 
					
						
							|  |  |  | 	for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { | 
					
						
							|  |  |  | 		for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { | 
					
						
							|  |  |  | 			region_check_fences(reg); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | void __ast_free(void *ptr, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!ptr) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	reg = region_remove(ptr); | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	if (reg) { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		region_check_fences(reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (reg->len <= MINNOWS_MAX_SIZE) { | 
					
						
							|  |  |  | 			region_free(&minnows, reg); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			region_free(&whales, reg); | 
					
						
							| 
									
										
										
										
											2005-09-29 04:34:11 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-05-06 00:01:32 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * This memory region is not registered.  It could be because of | 
					
						
							|  |  |  | 		 * a double free or the memory block was not allocated by the | 
					
						
							|  |  |  | 		 * malloc debug code. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		astmm_log("WARNING: Freeing unregistered memory %p by %s %s() line %d\n", | 
					
						
							|  |  |  | 			ptr, file, func, lineno); | 
					
						
							|  |  |  | 		my_do_crash(); | 
					
						
							| 
									
										
										
										
											2003-05-06 00:01:32 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | void *__ast_repl_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	void *ptr; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 0); | 
					
						
							|  |  |  | 	if (ptr) { | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 		memset(ptr, 0, size * nmemb); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | static void *__ast_repl_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	void *ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func, 1); | 
					
						
							|  |  |  | 	if (ptr) { | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 		memset(ptr, 0, size * nmemb); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | void *__ast_repl_malloc(size_t size, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	void *ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ptr = __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func, 0); | 
					
						
							|  |  |  | 	if (ptr) { | 
					
						
							|  |  |  | 		/* Make sure that the malloced memory is not zero. */ | 
					
						
							|  |  |  | 		memset(ptr, MALLOC_FILLER, size); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ptr; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \note reglock must be locked before calling. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct ast_region *region_find(void *ptr) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	int hash; | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	hash = HASH(ptr); | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	for (reg = regions[hash]; reg; reg = AST_LIST_NEXT(reg, node)) { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		if (reg->data == ptr) { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	return reg; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | void *__ast_repl_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	size_t len; | 
					
						
							|  |  |  | 	struct ast_region *found; | 
					
						
							|  |  |  | 	void *new_mem; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ptr) { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		ast_mutex_lock(®lock); | 
					
						
							|  |  |  | 		found = region_find(ptr); | 
					
						
							|  |  |  | 		if (!found) { | 
					
						
							|  |  |  | 			ast_mutex_unlock(®lock); | 
					
						
							|  |  |  | 			astmm_log("WARNING: Realloc of unregistered memory %p by %s %s() line %d\n", | 
					
						
							|  |  |  | 				ptr, file, func, lineno); | 
					
						
							|  |  |  | 			my_do_crash(); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		len = found->len; | 
					
						
							|  |  |  | 		ast_mutex_unlock(®lock); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		found = NULL; | 
					
						
							|  |  |  | 		len = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!size) { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 		__ast_free(ptr, file, lineno, func); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	new_mem = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func, 0); | 
					
						
							|  |  |  | 	if (new_mem) { | 
					
						
							|  |  |  | 		if (found) { | 
					
						
							|  |  |  | 			/* Copy the old data to the new malloced memory. */ | 
					
						
							|  |  |  | 			if (size <= len) { | 
					
						
							|  |  |  | 				memcpy(new_mem, ptr, size); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				memcpy(new_mem, ptr, len); | 
					
						
							|  |  |  | 				/* Make sure that the added memory is not zero. */ | 
					
						
							|  |  |  | 				memset(new_mem + len, MALLOC_FILLER, size - len); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 			__ast_free(ptr, file, lineno, func); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			/* Make sure that the malloced memory is not zero. */ | 
					
						
							|  |  |  | 			memset(new_mem, MALLOC_FILLER, size); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	return new_mem; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | char *__ast_repl_strdup(const char *s, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	size_t len; | 
					
						
							|  |  |  | 	void *ptr; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	len = strlen(s) + 1; | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	if ((ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func, 0))) { | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 		strcpy(ptr, s); | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | char *__ast_repl_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	size_t len; | 
					
						
							| 
									
										
										
										
											2012-09-07 23:10:05 +00:00
										 |  |  | 	char *ptr; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-07 23:10:05 +00:00
										 |  |  | 	len = strnlen(s, n); | 
					
						
							|  |  |  | 	if ((ptr = __ast_alloc_region(len + 1, FUNC_STRNDUP, file, lineno, func, 0))) { | 
					
						
							|  |  |  | 		memcpy(ptr, s, len); | 
					
						
							|  |  |  | 		ptr[len] = '\0'; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | int __ast_repl_asprintf(const char *file, int lineno, const char *func, char **strp, const char *fmt, ...) | 
					
						
							| 
									
										
										
										
											2006-01-04 21:54:09 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int size; | 
					
						
							|  |  |  | 	va_list ap, ap2; | 
					
						
							|  |  |  | 	char s; | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	void *ptr; | 
					
						
							| 
									
										
										
										
											2006-01-04 21:54:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	va_start(ap, fmt); | 
					
						
							|  |  |  | 	va_copy(ap2, ap); | 
					
						
							|  |  |  | 	size = vsnprintf(&s, 1, fmt, ap2); | 
					
						
							|  |  |  | 	va_end(ap2); | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	ptr = __ast_alloc_region(size + 1, FUNC_ASPRINTF, file, lineno, func, 0); | 
					
						
							|  |  |  | 	if (!ptr) { | 
					
						
							|  |  |  | 		/* As with stdlib *strp is undefined if allocation fails. */ | 
					
						
							| 
									
										
										
										
											2006-01-04 21:54:09 +00:00
										 |  |  | 		va_end(ap); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	vsnprintf(ptr, size + 1, fmt, ap); | 
					
						
							| 
									
										
										
										
											2006-01-04 21:54:09 +00:00
										 |  |  | 	va_end(ap); | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	*strp = ptr; | 
					
						
							| 
									
										
										
										
											2006-01-04 21:54:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | int __ast_repl_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2004-01-14 06:35:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-16 02:20:16 +00:00
										 |  |  | 	int size; | 
					
						
							|  |  |  | 	va_list ap2; | 
					
						
							|  |  |  | 	char s; | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	void *ptr; | 
					
						
							| 
									
										
										
										
											2005-11-16 02:20:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	va_copy(ap2, ap); | 
					
						
							|  |  |  | 	size = vsnprintf(&s, 1, fmt, ap2); | 
					
						
							|  |  |  | 	va_end(ap2); | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	ptr = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func, 0); | 
					
						
							|  |  |  | 	if (!ptr) { | 
					
						
							|  |  |  | 		/* As with stdlib *strp is undefined if allocation fails. */ | 
					
						
							| 
									
										
										
										
											2005-11-16 02:20:16 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2006-01-04 21:54:09 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	vsnprintf(ptr, size + 1, fmt, ap); | 
					
						
							|  |  |  | 	*strp = ptr; | 
					
						
							| 
									
										
										
										
											2005-11-16 02:20:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return size; | 
					
						
							| 
									
										
										
										
											2004-01-14 06:35:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Count the number of bytes in the specified freed region. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param freed Already freed region blocks storage. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note reglock must be locked before calling. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Number of bytes in freed region. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static size_t freed_regions_size(struct ast_freed_regions *freed) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	size_t total_len = 0; | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 	struct ast_region *old; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) { | 
					
						
							|  |  |  | 		old = freed->regions[idx]; | 
					
						
							|  |  |  | 		if (old) { | 
					
						
							|  |  |  | 			total_len += old->len; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return total_len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | static char *handle_memory_atexit_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							| 
									
										
										
										
											2017-02-11 10:57:03 -05:00
										 |  |  | 		e->command = "memory atexit list {on|off}"; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 		e->usage = | 
					
						
							|  |  |  | 			"Usage: memory atexit list {on|off}\n" | 
					
						
							|  |  |  | 			"       Enable dumping a list of still allocated memory segments at exit.\n"; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc != 4) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_true(a->argv[3])) { | 
					
						
							|  |  |  | 		atexit_list = 1; | 
					
						
							|  |  |  | 	} else if (ast_false(a->argv[3])) { | 
					
						
							|  |  |  | 		atexit_list = 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_cli(a->fd, "The atexit list is: %s\n", atexit_list ? "On" : "Off"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return CLI_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char buf[80]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							| 
									
										
										
										
											2017-02-11 10:57:03 -05:00
										 |  |  | 		e->command = "memory atexit summary {off|byline|byfunc|byfile}"; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 		e->usage = | 
					
						
							|  |  |  | 			"Usage: memory atexit summary {off|byline|byfunc|byfile}\n" | 
					
						
							|  |  |  | 			"       Summary of still allocated memory segments at exit options.\n" | 
					
						
							|  |  |  | 			"       off - Disable at exit summary.\n" | 
					
						
							|  |  |  | 			"       byline - Enable at exit summary by file line number.\n" | 
					
						
							|  |  |  | 			"       byfunc - Enable at exit summary by function name.\n" | 
					
						
							|  |  |  | 			"       byfile - Enable at exit summary by file.\n" | 
					
						
							|  |  |  | 			"\n" | 
					
						
							|  |  |  | 			"       Note: byline, byfunc, and byfile are cumulative enables.\n"; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc != 4) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_false(a->argv[3])) { | 
					
						
							|  |  |  | 		atexit_summary = SUMMARY_OFF; | 
					
						
							|  |  |  | 	} else if (!strcasecmp(a->argv[3], "byline")) { | 
					
						
							|  |  |  | 		atexit_summary |= SUMMARY_BY_LINE; | 
					
						
							|  |  |  | 	} else if (!strcasecmp(a->argv[3], "byfunc")) { | 
					
						
							|  |  |  | 		atexit_summary |= SUMMARY_BY_FUNC; | 
					
						
							|  |  |  | 	} else if (!strcasecmp(a->argv[3], "byfile")) { | 
					
						
							|  |  |  | 		atexit_summary |= SUMMARY_BY_FILE; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (atexit_summary) { | 
					
						
							|  |  |  | 		buf[0] = '\0'; | 
					
						
							|  |  |  | 		if (atexit_summary & SUMMARY_BY_LINE) { | 
					
						
							|  |  |  | 			strcat(buf, "byline"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (atexit_summary & SUMMARY_BY_FUNC) { | 
					
						
							|  |  |  | 			if (buf[0]) { | 
					
						
							|  |  |  | 				strcat(buf, " | "); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			strcat(buf, "byfunc"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (atexit_summary & SUMMARY_BY_FILE) { | 
					
						
							|  |  |  | 			if (buf[0]) { | 
					
						
							|  |  |  | 				strcat(buf, " | "); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			strcat(buf, "byfile"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		strcpy(buf, "Off"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_cli(a->fd, "The atexit summary is: %s\n", buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return CLI_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Common summary output at the end of the memory show commands. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param fd CLI output file descriptor. | 
					
						
							|  |  |  |  * \param whales_len Accumulated size of free large allocations. | 
					
						
							|  |  |  |  * \param minnows_len Accumulated size of free small allocations. | 
					
						
							|  |  |  |  * \param total_len Accumulated size of all current allocations. | 
					
						
							|  |  |  |  * \param selected_len Accumulated size of the selected allocations. | 
					
						
							|  |  |  |  * \param cache_len Accumulated size of the allocations that are part of a cache. | 
					
						
							|  |  |  |  * \param count Number of selected allocations. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void print_memory_show_common_stats(int fd, | 
					
						
							|  |  |  | 	unsigned int whales_len, | 
					
						
							|  |  |  | 	unsigned int minnows_len, | 
					
						
							|  |  |  | 	unsigned int total_len, | 
					
						
							|  |  |  | 	unsigned int selected_len, | 
					
						
							|  |  |  | 	unsigned int cache_len, | 
					
						
							|  |  |  | 	unsigned int count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (cache_len) { | 
					
						
							|  |  |  | 		ast_cli(fd, "%10u bytes allocated (%u in caches) in %u selected allocations\n\n", | 
					
						
							|  |  |  | 			selected_len, cache_len, count); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_cli(fd, "%10u bytes allocated in %u selected allocations\n\n", | 
					
						
							|  |  |  | 			selected_len, count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_cli(fd, "%10u bytes in all allocations\n", total_len); | 
					
						
							|  |  |  | 	ast_cli(fd, "%10u bytes in deferred free large allocations\n", whales_len); | 
					
						
							|  |  |  | 	ast_cli(fd, "%10u bytes in deferred free small allocations\n", minnows_len); | 
					
						
							|  |  |  | 	ast_cli(fd, "%10u bytes in deferred free allocations\n", | 
					
						
							|  |  |  | 		whales_len + minnows_len); | 
					
						
							|  |  |  | 	ast_cli(fd, "%10u bytes in all allocations and deferred free allocations\n", | 
					
						
							|  |  |  | 		total_len + whales_len + minnows_len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-22 16:53:41 +00:00
										 |  |  | 	const char *fn = NULL; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	struct ast_region *reg; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	unsigned int idx; | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 	unsigned int whales_len; | 
					
						
							|  |  |  | 	unsigned int minnows_len; | 
					
						
							|  |  |  | 	unsigned int total_len = 0; | 
					
						
							|  |  |  | 	unsigned int selected_len = 0; | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 	unsigned int cache_len = 0; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	unsigned int count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							|  |  |  | 		e->command = "memory show allocations"; | 
					
						
							|  |  |  | 		e->usage = | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 			"Usage: memory show allocations [<file>|anomalies]\n" | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 			"       Dumps a list of segments of allocated memory.\n" | 
					
						
							|  |  |  | 			"       Defaults to listing all memory allocations.\n" | 
					
						
							|  |  |  | 			"       <file> - Restricts output to memory allocated by the file.\n" | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 			"       anomalies - Only check for fence violations.\n"; | 
					
						
							| 
									
										
										
										
											2007-11-06 19:51:37 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	if (a->argc == 4) { | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 		fn = a->argv[3]; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	} else if (a->argc != 3) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Look for historical misspelled option as well. */ | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	if (fn && (!strcasecmp(fn, "anomalies") || !strcasecmp(fn, "anomolies"))) { | 
					
						
							|  |  |  | 		regions_check_all_fences(); | 
					
						
							|  |  |  | 		ast_cli(a->fd, "Anomaly check complete.\n"); | 
					
						
							|  |  |  | 		return CLI_SUCCESS; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-29 19:47:52 +00:00
										 |  |  | 	ast_mutex_lock(®lock); | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { | 
					
						
							|  |  |  | 		for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 			total_len += reg->len; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 			if (fn && strcasecmp(fn, reg->file)) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			region_check_fences(reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ast_cli(a->fd, "%10u bytes allocated%s by %20s() line %5u of %s\n", | 
					
						
							|  |  |  | 				(unsigned int) reg->len, reg->cache ? " (cache)" : "", | 
					
						
							|  |  |  | 				reg->func, reg->lineno, reg->file); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 			selected_len += reg->len; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 			if (reg->cache) { | 
					
						
							|  |  |  | 				cache_len += reg->len; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 			++count; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	whales_len = freed_regions_size(&whales); | 
					
						
							|  |  |  | 	minnows_len = freed_regions_size(&minnows); | 
					
						
							| 
									
										
										
										
											2007-10-29 19:47:52 +00:00
										 |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 	print_memory_show_common_stats(a->fd, | 
					
						
							|  |  |  | 		whales_len, minnows_len, total_len, | 
					
						
							|  |  |  | 		selected_len, cache_len, count); | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 	return CLI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | #define my_max(a, b) ((a) >= (b) ? (a) : (b))
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-22 16:53:41 +00:00
										 |  |  | 	const char *fn = NULL; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	int idx; | 
					
						
							|  |  |  | 	int cmp; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	struct ast_region *reg; | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 	unsigned int whales_len; | 
					
						
							|  |  |  | 	unsigned int minnows_len; | 
					
						
							|  |  |  | 	unsigned int total_len = 0; | 
					
						
							|  |  |  | 	unsigned int selected_len = 0; | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 	unsigned int cache_len = 0; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	unsigned int count = 0; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	struct file_summary { | 
					
						
							|  |  |  | 		struct file_summary *next; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 		unsigned int len; | 
					
						
							|  |  |  | 		unsigned int cache_len; | 
					
						
							|  |  |  | 		unsigned int count; | 
					
						
							|  |  |  | 		unsigned int lineno; | 
					
						
							|  |  |  | 		char name[my_max(sizeof(reg->file), sizeof(reg->func))]; | 
					
						
							|  |  |  | 	} *list = NULL, *cur, **prev; | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							|  |  |  | 		e->command = "memory show summary"; | 
					
						
							|  |  |  | 		e->usage = | 
					
						
							|  |  |  | 			"Usage: memory show summary [<file>]\n" | 
					
						
							|  |  |  | 			"       Summarizes heap memory allocations by file, or optionally\n" | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 			"       by line if a file is specified.\n"; | 
					
						
							| 
									
										
										
										
											2007-11-07 00:16:03 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	if (a->argc == 4) { | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 		fn = a->argv[3]; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	} else if (a->argc != 3) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-13 15:25:16 +00:00
										 |  |  | 	ast_mutex_lock(®lock); | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 	for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 		for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 			total_len += reg->len; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 			if (fn) { | 
					
						
							|  |  |  | 				if (strcasecmp(fn, reg->file)) { | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* Sort list by func/lineno.  Find existing or place to insert. */ | 
					
						
							|  |  |  | 				for (prev = &list; (cur = *prev); prev = &cur->next) { | 
					
						
							|  |  |  | 					cmp = strcmp(cur->name, reg->func); | 
					
						
							|  |  |  | 					if (cmp < 0) { | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (cmp > 0) { | 
					
						
							|  |  |  | 						/* Insert before current */ | 
					
						
							|  |  |  | 						cur = NULL; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					cmp = cur->lineno - reg->lineno; | 
					
						
							|  |  |  | 					if (cmp < 0) { | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (cmp > 0) { | 
					
						
							|  |  |  | 						/* Insert before current */ | 
					
						
							|  |  |  | 						cur = NULL; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				/* Sort list by filename.  Find existing or place to insert. */ | 
					
						
							|  |  |  | 				for (prev = &list; (cur = *prev); prev = &cur->next) { | 
					
						
							|  |  |  | 					cmp = strcmp(cur->name, reg->file); | 
					
						
							|  |  |  | 					if (cmp < 0) { | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (cmp > 0) { | 
					
						
							|  |  |  | 						/* Insert before current */ | 
					
						
							|  |  |  | 						cur = NULL; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 			if (!cur) { | 
					
						
							| 
									
										
										
										
											2012-07-31 20:21:43 +00:00
										 |  |  | 				cur = ast_alloca(sizeof(*cur)); | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 				memset(cur, 0, sizeof(*cur)); | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 				cur->lineno = reg->lineno; | 
					
						
							|  |  |  | 				ast_copy_string(cur->name, fn ? reg->func : reg->file, sizeof(cur->name)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				cur->next = *prev; | 
					
						
							|  |  |  | 				*prev = cur; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			cur->len += reg->len; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 			if (reg->cache) { | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 				cur->cache_len += reg->len; | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			++cur->count; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	whales_len = freed_regions_size(&whales); | 
					
						
							|  |  |  | 	minnows_len = freed_regions_size(&minnows); | 
					
						
							| 
									
										
										
										
											2003-08-13 15:25:16 +00:00
										 |  |  | 	ast_mutex_unlock(®lock); | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	/* Dump the whole list */ | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 	for (cur = list; cur; cur = cur->next) { | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 		selected_len += cur->len; | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 		cache_len += cur->cache_len; | 
					
						
							| 
									
										
										
										
											2006-09-20 22:14:04 +00:00
										 |  |  | 		count += cur->count; | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 		if (cur->cache_len) { | 
					
						
							|  |  |  | 			if (fn) { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 				ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations by %20s() line %5u of %s\n", | 
					
						
							|  |  |  | 					cur->len, cur->cache_len, cur->count, cur->name, cur->lineno, fn); | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 				ast_cli(a->fd, "%10u bytes (%10u cache) in %10u allocations in file %s\n", | 
					
						
							|  |  |  | 					cur->len, cur->cache_len, cur->count, cur->name); | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-08-03 04:50:09 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 			if (fn) { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 				ast_cli(a->fd, "%10u bytes in %10u allocations by %20s() line %5u of %s\n", | 
					
						
							|  |  |  | 					cur->len, cur->count, cur->name, cur->lineno, fn); | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:07:55 +00:00
										 |  |  | 				ast_cli(a->fd, "%10u bytes in %10u allocations in file %s\n", | 
					
						
							|  |  |  | 					cur->len, cur->count, cur->name); | 
					
						
							| 
									
										
										
										
											2006-12-27 18:33:44 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-08-03 04:50:09 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-13 18:20:57 -06:00
										 |  |  | 	print_memory_show_common_stats(a->fd, | 
					
						
							|  |  |  | 		whales_len, minnows_len, total_len, | 
					
						
							|  |  |  | 		selected_len, cache_len, count); | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 23:14:30 +00:00
										 |  |  | 	return CLI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-27 18:52:23 +00:00
										 |  |  | static char *handle_memory_backtrace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							| 
									
										
										
										
											2017-02-11 10:57:03 -05:00
										 |  |  | 		e->command = "memory backtrace {on|off}"; | 
					
						
							| 
									
										
										
										
											2013-08-27 18:52:23 +00:00
										 |  |  | 		e->usage = | 
					
						
							|  |  |  | 			"Usage: memory backtrace {on|off}\n" | 
					
						
							|  |  |  | 			"       Enable dumping an allocation backtrace with memory diagnostics.\n" | 
					
						
							|  |  |  | 			"       Note that saving the backtrace data for each allocation\n" | 
					
						
							|  |  |  | 			"       can be CPU intensive.\n"; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc != 3) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_true(a->argv[2])) { | 
					
						
							|  |  |  | 		backtrace_enabled = 1; | 
					
						
							|  |  |  | 	} else if (ast_false(a->argv[2])) { | 
					
						
							|  |  |  | 		backtrace_enabled = 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_cli(a->fd, "The memory backtrace is: %s\n", backtrace_enabled ? "On" : "Off"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return CLI_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-18 19:54:18 +00:00
										 |  |  | static struct ast_cli_entry cli_memory[] = { | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	AST_CLI_DEFINE(handle_memory_atexit_list, "Enable memory allocations not freed at exit list."), | 
					
						
							|  |  |  | 	AST_CLI_DEFINE(handle_memory_atexit_summary, "Enable memory allocations not freed at exit summary."), | 
					
						
							|  |  |  | 	AST_CLI_DEFINE(handle_memory_show_allocations, "Display outstanding memory allocations"), | 
					
						
							| 
									
										
										
										
											2007-10-22 20:05:18 +00:00
										 |  |  | 	AST_CLI_DEFINE(handle_memory_show_summary, "Summarize outstanding memory allocations"), | 
					
						
							| 
									
										
										
										
											2013-08-27 18:52:23 +00:00
										 |  |  | 	AST_CLI_DEFINE(handle_memory_backtrace, "Enable dumping an allocation backtrace with memory diagnostics."), | 
					
						
							| 
									
										
										
										
											2006-09-18 19:54:18 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | AST_LIST_HEAD_NOLOCK(region_list, ast_region); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Convert the allocated regions hash table to a list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param list Fill list with the allocated regions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \details | 
					
						
							|  |  |  |  * Take all allocated regions from the regions[] and put them | 
					
						
							|  |  |  |  * into the list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note reglock must be locked before calling. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note This function is destructive to the regions[] lists. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Length of list created. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static size_t mm_atexit_hash_list(struct region_list *list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 	size_t total_length; | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	total_length = 0; | 
					
						
							|  |  |  | 	for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { | 
					
						
							|  |  |  | 		while ((reg = regions[idx])) { | 
					
						
							|  |  |  | 			regions[idx] = AST_LIST_NEXT(reg, node); | 
					
						
							|  |  |  | 			AST_LIST_NEXT(reg, node) = NULL; | 
					
						
							|  |  |  | 			AST_LIST_INSERT_HEAD(list, reg, node); | 
					
						
							|  |  |  | 			++total_length; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return total_length; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Put the regions list into the allocated regions hash table. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param list List to put into the allocated regions hash table. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note reglock must be locked before calling. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_hash_restore(struct region_list *list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 	int hash; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((reg = AST_LIST_REMOVE_HEAD(list, node))) { | 
					
						
							|  |  |  | 		hash = HASH(reg->data); | 
					
						
							|  |  |  | 		AST_LIST_NEXT(reg, node) = regions[hash]; | 
					
						
							|  |  |  | 		regions[hash] = reg; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Sort regions comparision. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param left Region to compare. | 
					
						
							|  |  |  |  * \param right Region to compare. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval <0 if left < right | 
					
						
							|  |  |  |  * \retval =0 if left == right | 
					
						
							|  |  |  |  * \retval >0 if left > right | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int mm_atexit_cmp(struct ast_region *left, struct ast_region *right) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int cmp; | 
					
						
							|  |  |  | 	ptrdiff_t cmp_ptr; | 
					
						
							|  |  |  | 	ssize_t cmp_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Sort by filename. */ | 
					
						
							|  |  |  | 	cmp = strcmp(left->file, right->file); | 
					
						
							|  |  |  | 	if (cmp) { | 
					
						
							|  |  |  | 		return cmp; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Sort by line number. */ | 
					
						
							|  |  |  | 	cmp = left->lineno - right->lineno; | 
					
						
							|  |  |  | 	if (cmp) { | 
					
						
							|  |  |  | 		return cmp; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Sort by allocated size. */ | 
					
						
							|  |  |  | 	cmp_size = left->len - right->len; | 
					
						
							|  |  |  | 	if (cmp_size) { | 
					
						
							|  |  |  | 		if (cmp_size < 0) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Sort by allocated pointers just because. */ | 
					
						
							|  |  |  | 	cmp_ptr = left->data - right->data; | 
					
						
							|  |  |  | 	if (cmp_ptr) { | 
					
						
							|  |  |  | 		if (cmp_ptr < 0) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Merge the given sorted sublists into sorted order onto the end of the list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param list Merge sublists onto this list. | 
					
						
							|  |  |  |  * \param sub1 First sublist to merge. | 
					
						
							|  |  |  |  * \param sub2 Second sublist to merge. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_list_merge(struct region_list *list, struct region_list *sub1, struct region_list *sub2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		if (AST_LIST_EMPTY(sub1)) { | 
					
						
							|  |  |  | 			/* The remaining sublist goes onto the list. */ | 
					
						
							|  |  |  | 			AST_LIST_APPEND_LIST(list, sub2, node); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (AST_LIST_EMPTY(sub2)) { | 
					
						
							|  |  |  | 			/* The remaining sublist goes onto the list. */ | 
					
						
							|  |  |  | 			AST_LIST_APPEND_LIST(list, sub1, node); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (mm_atexit_cmp(AST_LIST_FIRST(sub1), AST_LIST_FIRST(sub2)) <= 0) { | 
					
						
							|  |  |  | 			reg = AST_LIST_REMOVE_HEAD(sub1, node); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			reg = AST_LIST_REMOVE_HEAD(sub2, node); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		AST_LIST_INSERT_TAIL(list, reg, node); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Take sublists off of the given list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param list Source list to remove sublists from the beginning of list. | 
					
						
							|  |  |  |  * \param sub Array of sublists to fill. (Lists are empty on entry.) | 
					
						
							|  |  |  |  * \param num_lists Number of lists to remove from the source list. | 
					
						
							|  |  |  |  * \param size Size of the sublists to remove. | 
					
						
							|  |  |  |  * \param remaining Remaining number of elements on the source list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_list_split(struct region_list *list, struct region_list sub[], size_t num_lists, size_t size, size_t *remaining) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (idx = 0; idx < num_lists; ++idx) { | 
					
						
							|  |  |  | 		size_t count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (*remaining < size) { | 
					
						
							|  |  |  | 			/* The remaining source list goes onto the sublist. */ | 
					
						
							|  |  |  | 			AST_LIST_APPEND_LIST(&sub[idx], list, node); | 
					
						
							|  |  |  | 			*remaining = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Take a sublist off the beginning of the source list. */ | 
					
						
							|  |  |  | 		*remaining -= size; | 
					
						
							|  |  |  | 		for (count = size; count--;) { | 
					
						
							|  |  |  | 			struct ast_region *reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			reg = AST_LIST_REMOVE_HEAD(list, node); | 
					
						
							|  |  |  | 			AST_LIST_INSERT_TAIL(&sub[idx], reg, node); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Sort the regions list using mergesort. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param list Allocated regions list to sort. | 
					
						
							|  |  |  |  * \param length Length of the list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_list_sort(struct region_list *list, size_t length) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*! Semi-sorted merged list. */ | 
					
						
							|  |  |  | 	struct region_list merged = AST_LIST_HEAD_NOLOCK_INIT_VALUE; | 
					
						
							|  |  |  | 	/*! Sublists to merge. (Can only merge two sublists at this time.) */ | 
					
						
							|  |  |  | 	struct region_list sub[2] = { | 
					
						
							|  |  |  | 		AST_LIST_HEAD_NOLOCK_INIT_VALUE, | 
					
						
							|  |  |  | 		AST_LIST_HEAD_NOLOCK_INIT_VALUE | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	/*! Sublist size. */ | 
					
						
							|  |  |  | 	size_t size = 1; | 
					
						
							|  |  |  | 	/*! Remaining elements in the list. */ | 
					
						
							|  |  |  | 	size_t remaining; | 
					
						
							|  |  |  | 	/*! Number of sublist merge passes to process the list. */ | 
					
						
							|  |  |  | 	int passes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		remaining = length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		passes = 0; | 
					
						
							|  |  |  | 		while (!AST_LIST_EMPTY(list)) { | 
					
						
							|  |  |  | 			mm_atexit_list_split(list, sub, ARRAY_LEN(sub), size, &remaining); | 
					
						
							|  |  |  | 			mm_atexit_list_merge(&merged, &sub[0], &sub[1]); | 
					
						
							|  |  |  | 			++passes; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		AST_LIST_APPEND_LIST(list, &merged, node); | 
					
						
							|  |  |  | 		if (passes <= 1) { | 
					
						
							|  |  |  | 			/* The list is now sorted. */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Double the sublist size to remove for next round. */ | 
					
						
							|  |  |  | 		size <<= 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief List all regions currently allocated. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param alloced regions list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_regions_list(struct region_list *alloced) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(alloced, reg, node) { | 
					
						
							|  |  |  | 		astmm_log("%s %s() line %u: %u bytes%s at %p\n", | 
					
						
							|  |  |  | 			reg->file, reg->func, reg->lineno, | 
					
						
							|  |  |  | 			(unsigned int) reg->len, reg->cache ? " (cache)" : "", reg->data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Summarize all regions currently allocated. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param alloced Sorted regions list. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_regions_summary(struct region_list *alloced) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_region *reg; | 
					
						
							|  |  |  | 	struct ast_region *next; | 
					
						
							|  |  |  | 	struct { | 
					
						
							|  |  |  | 		unsigned int count; | 
					
						
							|  |  |  | 		unsigned int len; | 
					
						
							|  |  |  | 		unsigned int cache_len; | 
					
						
							|  |  |  | 	} by_line, by_func, by_file, total; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	by_line.count = 0; | 
					
						
							|  |  |  | 	by_line.len = 0; | 
					
						
							|  |  |  | 	by_line.cache_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	by_func.count = 0; | 
					
						
							|  |  |  | 	by_func.len = 0; | 
					
						
							|  |  |  | 	by_func.cache_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	by_file.count = 0; | 
					
						
							|  |  |  | 	by_file.len = 0; | 
					
						
							|  |  |  | 	by_file.cache_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	total.count = 0; | 
					
						
							|  |  |  | 	total.len = 0; | 
					
						
							|  |  |  | 	total.cache_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(alloced, reg, node) { | 
					
						
							|  |  |  | 		next = AST_LIST_NEXT(reg, node); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		++by_line.count; | 
					
						
							|  |  |  | 		by_line.len += reg->len; | 
					
						
							|  |  |  | 		if (reg->cache) { | 
					
						
							|  |  |  | 			by_line.cache_len += reg->len; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (next && !strcmp(reg->file, next->file) && reg->lineno == next->lineno) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (atexit_summary & SUMMARY_BY_LINE) { | 
					
						
							|  |  |  | 			if (by_line.cache_len) { | 
					
						
							|  |  |  | 				astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s() line %u\n", | 
					
						
							|  |  |  | 					by_line.len, by_line.cache_len, by_line.count, reg->file, reg->func, reg->lineno); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				astmm_log("%10u bytes in %5u allocations. %s %s() line %u\n", | 
					
						
							|  |  |  | 					by_line.len, by_line.count, reg->file, reg->func, reg->lineno); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		by_func.count += by_line.count; | 
					
						
							|  |  |  | 		by_func.len += by_line.len; | 
					
						
							|  |  |  | 		by_func.cache_len += by_line.cache_len; | 
					
						
							|  |  |  | 		by_line.count = 0; | 
					
						
							|  |  |  | 		by_line.len = 0; | 
					
						
							|  |  |  | 		by_line.cache_len = 0; | 
					
						
							|  |  |  | 		if (next && !strcmp(reg->file, next->file) && !strcmp(reg->func, next->func)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (atexit_summary & SUMMARY_BY_FUNC) { | 
					
						
							|  |  |  | 			if (by_func.cache_len) { | 
					
						
							|  |  |  | 				astmm_log("%10u bytes (%u in caches) in %u allocations. %s %s()\n", | 
					
						
							|  |  |  | 					by_func.len, by_func.cache_len, by_func.count, reg->file, reg->func); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				astmm_log("%10u bytes in %5u allocations. %s %s()\n", | 
					
						
							|  |  |  | 					by_func.len, by_func.count, reg->file, reg->func); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		by_file.count += by_func.count; | 
					
						
							|  |  |  | 		by_file.len += by_func.len; | 
					
						
							|  |  |  | 		by_file.cache_len += by_func.cache_len; | 
					
						
							|  |  |  | 		by_func.count = 0; | 
					
						
							|  |  |  | 		by_func.len = 0; | 
					
						
							|  |  |  | 		by_func.cache_len = 0; | 
					
						
							|  |  |  | 		if (next && !strcmp(reg->file, next->file)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (atexit_summary & SUMMARY_BY_FILE) { | 
					
						
							|  |  |  | 			if (by_file.cache_len) { | 
					
						
							|  |  |  | 				astmm_log("%10u bytes (%u in caches) in %u allocations. %s\n", | 
					
						
							|  |  |  | 					by_file.len, by_file.cache_len, by_file.count, reg->file); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				astmm_log("%10u bytes in %5u allocations. %s\n", | 
					
						
							|  |  |  | 					by_file.len, by_file.count, reg->file); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		total.count += by_file.count; | 
					
						
							|  |  |  | 		total.len += by_file.len; | 
					
						
							|  |  |  | 		total.cache_len += by_file.cache_len; | 
					
						
							|  |  |  | 		by_file.count = 0; | 
					
						
							|  |  |  | 		by_file.len = 0; | 
					
						
							|  |  |  | 		by_file.cache_len = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (total.cache_len) { | 
					
						
							|  |  |  | 		astmm_log("%u bytes (%u in caches) in %u allocations.\n", | 
					
						
							|  |  |  | 			total.len, total.cache_len, total.count); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		astmm_log("%u bytes in %u allocations.\n", total.len, total.count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Dump the memory allocations atexit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note reglock must be locked before calling. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_dump(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct region_list alloced_atexit = AST_LIST_HEAD_NOLOCK_INIT_VALUE; | 
					
						
							|  |  |  | 	size_t length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	length = mm_atexit_hash_list(&alloced_atexit); | 
					
						
							|  |  |  | 	if (!length) { | 
					
						
							|  |  |  | 		/* Wow!  This is amazing! */ | 
					
						
							|  |  |  | 		astmm_log("Exiting with all memory freed.\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mm_atexit_list_sort(&alloced_atexit, length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	astmm_log("Exiting with the following memory not freed:\n"); | 
					
						
							|  |  |  | 	if (atexit_list) { | 
					
						
							|  |  |  | 		mm_atexit_regions_list(&alloced_atexit); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (atexit_summary) { | 
					
						
							|  |  |  | 		mm_atexit_regions_summary(&alloced_atexit); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Put the alloced list back into regions[]. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2017-12-20 12:14:54 -05:00
										 |  |  | 	 * We have do this because we can get called before all other | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	 * threads have terminated. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	mm_atexit_hash_restore(&alloced_atexit); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_final(void) | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	FILE *log; | 
					
						
							| 
									
										
										
										
											2008-07-11 14:16:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-07 23:45:15 +00:00
										 |  |  | 	/* Only wait if we want atexit allocation dumps. */ | 
					
						
							|  |  |  | 	if (atexit_list || atexit_summary) { | 
					
						
							|  |  |  | 		fprintf(stderr, "Waiting 10 seconds to let other threads die.\n"); | 
					
						
							|  |  |  | 		sleep(10); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	regions_check_all_fences(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	/* Flush all delayed memory free circular arrays. */ | 
					
						
							|  |  |  | 	freed_regions_flush(&whales); | 
					
						
							|  |  |  | 	freed_regions_flush(&minnows); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 00:48:12 +00:00
										 |  |  | 	/* Peform atexit allocation dumps. */ | 
					
						
							|  |  |  | 	if (atexit_list || atexit_summary) { | 
					
						
							|  |  |  | 		ast_mutex_lock(®lock); | 
					
						
							|  |  |  | 		mm_atexit_dump(); | 
					
						
							|  |  |  | 		ast_mutex_unlock(®lock); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	/* Close the log file. */ | 
					
						
							|  |  |  | 	log = mmlog; | 
					
						
							|  |  |  | 	mmlog = NULL; | 
					
						
							|  |  |  | 	if (log) { | 
					
						
							|  |  |  | 		fclose(log); | 
					
						
							| 
									
										
										
										
											2008-07-11 14:16:15 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 00:54:11 -04:00
										 |  |  | void load_astmm_phase_1(void) | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	atexit(mm_atexit_final); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void mm_atexit_ast(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_cli_unregister_multiple(cli_memory, ARRAY_LEN(cli_memory)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 00:54:11 -04:00
										 |  |  | void load_astmm_phase_2(void) | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char filename[PATH_MAX]; | 
					
						
							| 
									
										
										
										
											2006-08-21 19:18:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-05 10:31:25 +00:00
										 |  |  | 	ast_cli_register_multiple(cli_memory, ARRAY_LEN(cli_memory)); | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-18 09:46:18 +00:00
										 |  |  | 	snprintf(filename, sizeof(filename), "%s/mmlog", ast_config_AST_LOG_DIR); | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 	ast_verb(1, "Asterisk Malloc Debugger Started (see %s))\n", filename); | 
					
						
							| 
									
										
										
										
											2012-03-22 19:51:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	mmlog = fopen(filename, "a+"); | 
					
						
							|  |  |  | 	if (mmlog) { | 
					
						
							|  |  |  | 		fprintf(mmlog, "%ld - New session\n", (long) time(NULL)); | 
					
						
							| 
									
										
										
										
											2003-05-08 18:51:06 +00:00
										 |  |  | 		fflush(mmlog); | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Could not open malloc debug log file: %s\n", filename); | 
					
						
							| 
									
										
										
										
											2003-05-08 18:51:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 22:24:26 +00:00
										 |  |  | 	ast_register_cleanup(mm_atexit_ast); | 
					
						
							| 
									
										
										
										
											2003-04-28 19:58:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | #else	/* !defined(__AST_DEBUG_MALLOC) */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 00:54:11 -04:00
										 |  |  | void load_astmm_phase_1(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void load_astmm_phase_2(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | void *__ast_repl_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return calloc(nmemb, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | static void *__ast_repl_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func) | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return calloc(nmemb, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *__ast_repl_malloc(size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return malloc(size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void __ast_free(void *ptr, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free(ptr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *__ast_repl_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return realloc(ptr, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *__ast_repl_strdup(const char *s, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return strdup(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *__ast_repl_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return strndup(s, n); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int __ast_repl_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	va_list ap; | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1); | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	va_start(ap, format); | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	res = vasprintf(strp, format, ap); | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	va_end(ap); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int __ast_repl_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | 	DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 	return vasprintf(strp, format, ap); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-08 17:38:31 +00:00
										 |  |  | #endif	/* defined(__AST_DEBUG_MALLOC) */
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 05:27:40 -04:00
										 |  |  | void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = __ast_repl_calloc(nmemb, size, file, lineno, func); | 
					
						
							|  |  |  | 	if (!p) { | 
					
						
							|  |  |  | 		MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *__ast_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = __ast_repl_calloc_cache(nmemb, size, file, lineno, func); | 
					
						
							|  |  |  | 	if (!p) { | 
					
						
							|  |  |  | 		MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = __ast_repl_malloc(size, file, lineno, func); | 
					
						
							|  |  |  | 	if (!p) { | 
					
						
							|  |  |  | 		MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *newp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	newp = __ast_repl_realloc(ptr, size, file, lineno, func); | 
					
						
							|  |  |  | 	if (!newp) { | 
					
						
							|  |  |  | 		MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return newp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *newstr = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s) { | 
					
						
							|  |  |  | 		newstr = __ast_repl_strdup(s, file, lineno, func); | 
					
						
							|  |  |  | 		if (!newstr) { | 
					
						
							|  |  |  | 			MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return newstr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *newstr = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s) { | 
					
						
							|  |  |  | 		newstr = __ast_repl_strndup(s, n, file, lineno, func); | 
					
						
							|  |  |  | 		if (!newstr) { | 
					
						
							|  |  |  | 			MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return newstr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res; | 
					
						
							|  |  |  | 	va_list ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_start(ap, format); | 
					
						
							|  |  |  | 	res = __ast_repl_vasprintf(strp, format, ap, file, lineno, func); | 
					
						
							|  |  |  | 	if (res < 0) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * *strp is undefined so set to NULL to ensure it is | 
					
						
							|  |  |  | 		 * initialized to something useful. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		*strp = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	va_end(ap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = __ast_repl_vasprintf(strp, format, ap, file, lineno, func); | 
					
						
							|  |  |  | 	if (res < 0) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * *strp is undefined so set to NULL to ensure it is | 
					
						
							|  |  |  | 		 * initialized to something useful. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		*strp = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		MALLOC_FAILURE_MSG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 19:55:50 -06:00
										 |  |  | void *ast_std_malloc(size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return malloc(size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *ast_std_calloc(size_t nmemb, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return calloc(nmemb, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *ast_std_realloc(void *ptr, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return realloc(ptr, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_std_free(void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free(ptr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_free_ptr(void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_free(ptr); | 
					
						
							|  |  |  | } |