From: Richard Mudgett Date: Tue, 27 Feb 2018 21:40:18 +0000 (-0600) Subject: pjproject: Add cache_pools debugging option. X-Git-Tag: 15.4.0-rc1~111^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f6d5bf99f295a4c6e77e41c5bee68bb232827db3;p=thirdparty%2Fasterisk.git pjproject: Add cache_pools debugging option. The pool cache gets in the way of finding use after free errors of memory pool contents. Tools like valgrind and MALLOC_DEBUG don't know when a pool is released because it gets put into the cache instead of being freed. * Added the "cache_pools" option to pjproject.conf. Disabling the option helps track down pool content mismanagement when using valgrind or MALLOC_DEBUG. The cache gets in the way of determining if the pool contents are used after free and who freed it. To disable the pool caching simply disable the cache_pools option in pjproject.conf and restart Asterisk. Sample pjproject.conf setting: [startup] cache_pools=no * Made current users of the caching pool factory initialization and destruction calls call common routines to create and destroy cached pools. ASTERISK-27704 Change-Id: I64d5befbaeed2532f93aa027a51eb52347d2b828 --- diff --git a/CHANGES b/CHANGES index 303544c9f3..84c302ae7f 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,17 @@ === ============================================================================== +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 15.3.0 to Asterisk 15.4.0 ------------ +------------------------------------------------------------------------------ + +res_pjproject +------------------ + * Added the "cache_pools" option to pjproject.conf. Disabling the option + helps track down pool content mismanagement when using valgrind or + MALLOC_DEBUG. The cache gets in the way of determining if the pool contents + are used after free and who freed it. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 15.2.0 to Asterisk 15.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/configs/samples/pjproject.conf.sample b/configs/samples/pjproject.conf.sample index 82c81a1f6e..03149c4539 100644 --- a/configs/samples/pjproject.conf.sample +++ b/configs/samples/pjproject.conf.sample @@ -5,6 +5,13 @@ ; NOTES: The name of this section in the pjproject.conf configuration file must ; remain startup or the configuration will not be applied. ; +;cache_pools = yes ; Cache pjproject memory pools for performance + ; Disable this option to help track down pool content + ; mismanagement when using valgrind or MALLOC_DEBUG. + ; The cache gets in the way of determining if the + ; pool contents are used after being freed and who + ; freed it. + ; Default yes ;log_level=default ; Initial maximum pjproject logging level to log ; Valid values are: 0-6, and default ; diff --git a/include/asterisk/options.h b/include/asterisk/options.h index 878748d169..78f596a884 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -173,6 +173,11 @@ enum ast_option_flags { /*! Current linked pjproject maximum logging level */ extern int ast_pjproject_max_log_level; +#define DEFAULT_PJPROJECT_CACHE_POOLS 1 + +/*! Current pjproject pool caching enable */ +extern int ast_option_pjproject_cache_pools; + /*! Current pjproject logging level */ extern int ast_option_pjproject_log_level; diff --git a/include/asterisk/res_pjproject.h b/include/asterisk/res_pjproject.h index 8828b340c8..27a2096b6c 100644 --- a/include/asterisk/res_pjproject.h +++ b/include/asterisk/res_pjproject.h @@ -19,6 +19,9 @@ #ifndef _RES_PJPROJECT_H #define _RES_PJPROJECT_H +#include +#include + /*! \brief Determines whether the res_pjproject module is loaded */ #define CHECK_PJPROJECT_MODULE_LOADED() \ do { \ @@ -93,4 +96,27 @@ void ast_pjproject_ref(void); */ void ast_pjproject_unref(void); +/*! + * \brief Initialize the caching pool factory. + * \since 13.21.0 + * + * \param cp Caching pool factory to initialize + * \param policy Pool factory policy + * \param max_capacity Total capacity to be retained in the cache. Zero disables caching. + * + * \return Nothing + */ +void ast_pjproject_caching_pool_init(pj_caching_pool *cp, + const pj_pool_factory_policy *policy, pj_size_t max_capacity); + +/*! + * \brief Destroy caching pool factory and all cached pools. + * \since 13.21.0 + * + * \param cp Caching pool factory to destroy + * + * \return Nothing + */ +void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp); + #endif /* _RES_PJPROJECT_H */ diff --git a/main/asterisk.c b/main/asterisk.c index 09914a2d69..e44c896ef8 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -332,6 +332,7 @@ int option_verbose; /*!< Verbosity level */ int option_debug; /*!< Debug level */ int ast_pjproject_max_log_level = -1;/* Default to -1 to know if we have read the level from pjproject yet. */ int ast_option_pjproject_log_level; +int ast_option_pjproject_cache_pools; double ast_option_maxload; /*!< Max load avg on system */ int ast_option_maxcalls; /*!< Max number of active calls */ int ast_option_maxfiles; /*!< Max number of open file handles (files, sockets) */ @@ -3768,6 +3769,7 @@ static void read_pjproject_startup_options(void) struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME }; ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL; + ast_option_pjproject_cache_pools = DEFAULT_PJPROJECT_CACHE_POOLS; cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags); if (!cfg @@ -3786,6 +3788,8 @@ static void read_pjproject_startup_options(void) } else if (MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level) { ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL; } + } else if (!strcasecmp(v->name, "cache_pools")) { + ast_option_pjproject_cache_pools = !ast_false(v->value); } } diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 6137898a31..8f7e8235f0 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -469,6 +469,18 @@ static struct ast_cli_entry pjproject_cli[] = { AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"), }; +void ast_pjproject_caching_pool_init(pj_caching_pool *cp, + const pj_pool_factory_policy *policy, pj_size_t max_capacity) +{ + /* Passing a max_capacity of zero disables caching pools */ + pj_caching_pool_init(cp, policy, ast_option_pjproject_cache_pools ? max_capacity : 0); +} + +void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp) +{ + pj_caching_pool_destroy(cp); +} + static int load_module(void) { ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n"); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 8849b0ba06..277606bb79 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4842,7 +4842,7 @@ static int unload_pjsip(void *data) ast_pjsip_endpoint = NULL; if (caching_pool.lock) { - pj_caching_pool_destroy(&caching_pool); + ast_pjproject_caching_pool_destroy(&caching_pool); } pj_shutdown(); @@ -4859,7 +4859,7 @@ static int load_pjsip(void) * example code from PJLIB. This can be adjusted * if necessary. */ - pj_caching_pool_init(&caching_pool, NULL, 1024 * 1024); + ast_pjproject_caching_pool_init(&caching_pool, NULL, 1024 * 1024); if (pjsip_endpt_create(&caching_pool.factory, "SIP", &ast_pjsip_endpoint) != PJ_SUCCESS) { ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n"); goto error; diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 7483a5b25c..2ce4a18696 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -17,8 +17,8 @@ */ #include "asterisk.h" -#include "pjsip.h" -#include "pjlib.h" +#include +#include #include "asterisk/res_pjsip.h" #include "asterisk/logger.h" diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index d6b3eebe9b..ba1b317b9d 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -42,6 +42,7 @@ #include "asterisk/netsock2.h" #include "asterisk/vector.h" #include "asterisk/lock.h" +#include "asterisk/res_pjproject.h" #define HISTORY_INITIAL_SIZE 256 @@ -1371,7 +1372,7 @@ static int load_module(void) ast_log(LOG_WARNING, "Unable to register history log level\n"); } - pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); + ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE); @@ -1389,7 +1390,7 @@ static int unload_module(void) ast_sip_push_task_synchronous(NULL, clear_history_entries, NULL); AST_VECTOR_FREE(&vector_history); - pj_caching_pool_destroy(&cachingpool); + ast_pjproject_caching_pool_destroy(&cachingpool); if (log_level != -1) { ast_logger_unregister_level("PJSIP_HISTORY"); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index d3273b463d..b53b38ad79 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -71,6 +71,9 @@ #include "asterisk/smoother.h" #include "asterisk/uuid.h" #include "asterisk/test.h" +#ifdef HAVE_PJPROJECT +#include "asterisk/res_pjproject.h" +#endif #define MAX_TIMESTAMP_SKEW 640 @@ -7376,7 +7379,7 @@ static void rtp_terminate_pjproject(void) pj_thread_destroy(timer_thread); } - pj_caching_pool_destroy(&cachingpool); + ast_pjproject_caching_pool_destroy(&cachingpool); pj_shutdown(); } #endif @@ -7401,7 +7404,7 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); + ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); pool = pj_pool_create(&cachingpool.factory, "timer", 512, 512, NULL);