From d5837ba8c275b75388815a3263dae97cf306161b Mon Sep 17 00:00:00 2001 From: Tilghman Lesher Date: Tue, 14 Oct 2008 22:38:06 +0000 Subject: [PATCH] Add additional memory debugging to several core APIs, and fix several memory leaks found with these changes. (Closes issue #13505, closes issue #13543) Reported by: mav3rick, triccyx Patches: 20081001__bug13505.diff.txt uploaded by Corydon76 (license 14) Tested by: mav3rick, triccyx git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@149199 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_sip.c | 6 ++++++ include/asterisk/chanvars.h | 5 +++++ include/asterisk/config.h | 5 +++++ include/asterisk/hashtab.h | 10 ++++++++++ include/asterisk/strings.h | 25 +++++++++++++++++++++++++ main/chanvars.c | 8 ++++++++ main/config.c | 8 ++++++++ main/hashtab.c | 24 +++++++++++++++++++++--- pbx/pbx_spool.c | 5 +++++ res/res_indications.c | 30 ++++++++++++++++++++++++++---- 10 files changed, 119 insertions(+), 7 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f535e3ed8e..8573e63163 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -21820,6 +21820,12 @@ static int reload_config(enum channelreloadreason reason) } /* Reset certificate handling for TLS sessions */ + if (reason != CHANNEL_MODULE_LOAD) { + ast_free(default_tls_cfg.certfile); + ast_free(default_tls_cfg.cipher); + ast_free(default_tls_cfg.cafile); + ast_free(default_tls_cfg.capath); + } default_tls_cfg.certfile = ast_strdup(AST_CERTFILE); /*XXX Not sure if this is useful */ default_tls_cfg.cipher = ast_strdup(""); default_tls_cfg.cafile = ast_strdup(""); diff --git a/include/asterisk/chanvars.h b/include/asterisk/chanvars.h index 63de58429c..7ebc64a9d4 100644 --- a/include/asterisk/chanvars.h +++ b/include/asterisk/chanvars.h @@ -33,7 +33,12 @@ struct ast_var_t { AST_LIST_HEAD_NOLOCK(varshead, ast_var_t); +#ifdef MALLOC_DEBUG +struct ast_var_t *_ast_var_assign(const char *name, const char *value, const char *file, int lineno, const char *function); +#define ast_var_assign(a,b) _ast_var_assign(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#else struct ast_var_t *ast_var_assign(const char *name, const char *value); +#endif void ast_var_delete(struct ast_var_t *var); const char *ast_var_name(const struct ast_var_t *var); const char *ast_var_full_name(const struct ast_var_t *var); diff --git a/include/asterisk/config.h b/include/asterisk/config.h index bd030a76ef..de42f25631 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -364,7 +364,12 @@ void ast_category_destroy(struct ast_category *cat); struct ast_variable *ast_category_detach_variables(struct ast_category *cat); void ast_category_rename(struct ast_category *cat, const char *name); +#ifdef MALLOC_DEBUG +struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *function, int lineno); +#define ast_variable_new(a, b, c) _ast_variable_new(a, b, c, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#else struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename); +#endif struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size); struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file); void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file); diff --git a/include/asterisk/hashtab.h b/include/asterisk/hashtab.h index aa4dc59db7..dbecaa2bc0 100644 --- a/include/asterisk/hashtab.h +++ b/include/asterisk/hashtab.h @@ -189,12 +189,22 @@ unsigned int ast_hashtab_hash_short(const short num); * \param hash a func ptr to do the hashing * \param do_locking use locks to guarantee safety of iterators/insertion/deletion -- real simpleminded right now */ +#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +struct ast_hashtab * _ast_hashtab_create(int initial_buckets, + int (*compare)(const void *a, const void *b), + int (*resize)(struct ast_hashtab *), + int (*newsize)(struct ast_hashtab *tab), + unsigned int (*hash)(const void *obj), + int do_locking, const char *file, int lineno, const char *function); +#define ast_hashtab_create(a,b,c,d,e,f) _ast_hashtab_create(a,b,c,d,e,f,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#else struct ast_hashtab * ast_hashtab_create(int initial_buckets, int (*compare)(const void *a, const void *b), int (*resize)(struct ast_hashtab *), int (*newsize)(struct ast_hashtab *tab), unsigned int (*hash)(const void *obj), int do_locking ); +#endif /*! * \brief This func will free the hash table and all its memory. diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 682524248e..19315b02f2 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -404,6 +404,30 @@ void ast_str_reset(struct ast_str *buf), /*! * Make space in a new string (e.g. to read in data from a file) */ +#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +AST_INLINE_API( +int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, int lineno, const char *function), +{ + _DB1(struct ast_str *old_buf = *buf;) + + if (new_len <= (*buf)->len) + return 0; /* success */ + if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC) + return -1; /* cannot extend */ + *buf = (struct ast_str *)__ast_realloc(*buf, new_len + sizeof(struct ast_str), file, lineno, function); + if (*buf == NULL) /* XXX watch out, we leak memory here */ + return -1; + if ((*buf)->ts != DS_MALLOC) { + pthread_setspecific((*buf)->ts->key, *buf); + _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));) + } + + (*buf)->len = new_len; + return 0; +} +) +#define ast_str_make_space(a,b) _ast_str_make_space(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#else AST_INLINE_API( int ast_str_make_space(struct ast_str **buf, size_t new_len), { @@ -425,6 +449,7 @@ int ast_str_make_space(struct ast_str **buf, size_t new_len), return 0; } ) +#endif #define ast_str_alloca(init_len) \ ({ \ diff --git a/main/chanvars.c b/main/chanvars.c index 14a89f7678..670858937a 100644 --- a/main/chanvars.c +++ b/main/chanvars.c @@ -31,13 +31,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/strings.h" #include "asterisk/utils.h" +#ifdef MALLOC_DEBUG +struct ast_var_t *_ast_var_assign(const char *name, const char *value, const char *file, int lineno, const char *function) +#else struct ast_var_t *ast_var_assign(const char *name, const char *value) +#endif { struct ast_var_t *var; int name_len = strlen(name) + 1; int value_len = strlen(value) + 1; +#ifdef MALLOC_DEBUG + if (!(var = __ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char), file, lineno, function))) { +#else if (!(var = ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char)))) { +#endif return NULL; } diff --git a/main/config.c b/main/config.c index 986c81571a..2055af396e 100644 --- a/main/config.c +++ b/main/config.c @@ -230,14 +230,22 @@ struct ast_config_include { struct ast_config_include *next; /*!< ptr to next inclusion in the list */ }; +#ifdef MALLOC_DEBUG +struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno) +#else struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) +#endif { struct ast_variable *variable; int name_len = strlen(name) + 1; int val_len = strlen(value) + 1; int fn_len = strlen(filename) + 1; +#ifdef MALLOC_DEBUG + if ((variable = __ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable), file, lineno, func))) { +#else if ((variable = ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable)))) { +#endif char *dst = variable->stuff; /* writable space starts here */ variable->name = strcpy(dst, name); dst += name_len; diff --git a/main/hashtab.c b/main/hashtab.c index a6fac4e536..d60a78a0eb 100644 --- a/main/hashtab.c +++ b/main/hashtab.c @@ -209,22 +209,40 @@ unsigned int ast_hashtab_hash_short(const short x) return x; } -struct ast_hashtab *ast_hashtab_create(int initial_buckets, +struct ast_hashtab * +#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +_ast_hashtab_create +#else +ast_hashtab_create +#endif +(int initial_buckets, int (*compare)(const void *a, const void *b), int (*resize)(struct ast_hashtab *), int (*newsize)(struct ast_hashtab *tab), unsigned int (*hash)(const void *obj), - int do_locking) + int do_locking +#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) + , const char *file, int lineno, const char *function +#endif +) { struct ast_hashtab *ht; - + +#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) + if (!(ht = __ast_calloc(1, sizeof(*ht), file, lineno, function))) +#else if (!(ht = ast_calloc(1, sizeof(*ht)))) +#endif return NULL; while (!ast_is_prime(initial_buckets)) /* make sure this is prime */ initial_buckets++; +#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) + if (!(ht->array = __ast_calloc(initial_buckets, sizeof(*(ht->array)), file, lineno, function))) { +#else if (!(ht->array = ast_calloc(initial_buckets, sizeof(*(ht->array))))) { +#endif free(ht); return NULL; } diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c index 37ff0edad9..26d38dfe5a 100644 --- a/pbx/pbx_spool.c +++ b/pbx/pbx_spool.c @@ -101,6 +101,9 @@ static void init_outgoing(struct outgoing *o) static void free_outgoing(struct outgoing *o) { + if (o->vars) { + ast_variables_destroy(o->vars); + } ast_free(o); } @@ -324,9 +327,11 @@ static void *attempt_thread(void *data) if (!ast_strlen_zero(o->app)) { ast_verb(3, "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries); res = ast_pbx_outgoing_app(o->tech, o->format, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL); + o->vars = NULL; } else { ast_verb(3, "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries); res = ast_pbx_outgoing_exten(o->tech, o->format, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL); + o->vars = NULL; } if (res) { ast_log(LOG_NOTICE, "Call failed to go through, reason (%d) %s\n", reason, ast_channel_reason2str(reason)); diff --git a/res/res_indications.c b/res/res_indications.c index 7fdca5be37..7f185f3199 100644 --- a/res/res_indications.c +++ b/res/res_indications.c @@ -249,6 +249,23 @@ static int handle_stopplaytones(struct ast_channel *chan, void *data) return 0; } +/* helper function to delete a tone_zone in its entirety */ +static inline void free_zone(struct ind_tone_zone* zone) +{ + while (zone->tones) { + struct ind_tone_zone_sound *tmp = zone->tones->next; + ast_free((void *)zone->tones->name); + ast_free((void *)zone->tones->data); + ast_free(zone->tones); + zone->tones = tmp; + } + + if (zone->ringcadence) + ast_free(zone->ringcadence); + + ast_free(zone); +} + /*! \brief load indications module */ static int ind_load_module(int reload) { @@ -303,6 +320,7 @@ static int ind_load_module(int reload) } if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) { ast_config_destroy(cfg); + free_zone(tones); return -1; } tones->ringcadence = tmp; @@ -319,13 +337,14 @@ static int ind_load_module(int reload) struct ind_tone_zone* azone; if (!(azone = ast_calloc(1, sizeof(*azone)))) { ast_config_destroy(cfg); + free_zone(tones); return -1; } ast_copy_string(azone->country, country, sizeof(azone->country)); ast_copy_string(azone->alias, cxt, sizeof(azone->alias)); if (ast_register_indication_country(azone)) { ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno); - ast_free(tones); + free_zone(tones); } /* next item */ country = strsep(&c,","); @@ -358,17 +377,20 @@ out: v = v->next; if (tones->description[0] || tones->alias[0] || tones->tones) { if (ast_register_indication_country(tones)) { ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno); - ast_free(tones); + free_zone(tones); } - } else ast_free(tones); + } else { + free_zone(tones); + } cxt = ast_category_browse(cfg, cxt); } /* determine which country is the default */ country = ast_variable_retrieve(cfg,"general","country"); - if (!country || !*country || ast_set_indication_country(country)) + if (ast_strlen_zero(country) || ast_set_indication_country(country)) { ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n"); + } ast_config_destroy(cfg); return 0;