From 27b69e7d29dc100e5fdf3cf911c3a02f3b5fd2b5 Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Fri, 27 Jan 2012 18:47:16 +0000
Subject: [PATCH] Audit of ao2_iterator_init() usage for v1.8.

Fixes numerous reference leaks and missing ao2_iterator_destroy() calls as
a result.

Review: https://reviewboard.asterisk.org/r/1697/
........

Merged revisions 352955 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 352956 from http://svn.asterisk.org/svn/asterisk/branches/10


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@352957 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/app_chanspy.c             | 13 +++++++---
 apps/app_queue.c               | 31 +++++++++++++----------
 channels/chan_iax2.c           | 16 +++++-------
 channels/chan_sip.c            | 10 +++++++-
 include/asterisk/indications.h |  3 ++-
 main/indications.c             |  2 ++
 main/pbx.c                     |  1 +
 main/taskprocessor.c           |  2 ++
 res/res_odbc.c                 |  5 +++-
 res/res_srtp.c                 | 46 ++++++++++++++++++----------------
 res/snmp/agent.c               |  9 +++++--
 11 files changed, 86 insertions(+), 52 deletions(-)

diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 54e4736816..4c709cfcc7 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -828,11 +828,13 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 		}
 
 		if (!iter) {
-			return -1;
+			res = -1;
+			goto exit;
 		}
 
 		res = ast_waitfordigit(chan, waitms);
 		if (res < 0) {
+			iter = ast_channel_iterator_destroy(iter);
 			ast_clear_flag(chan, AST_FLAG_SPYING);
 			break;
 		}
@@ -840,10 +842,12 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 			char tmp[2];
 			tmp[0] = res;
 			tmp[1] = '\0';
-			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
+			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
+				iter = ast_channel_iterator_destroy(iter);
 				goto exit;
-			else
+			} else {
 				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
+			}
 		}
 
 		/* reset for the next loop around, unless overridden later */
@@ -982,10 +986,12 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 
 			if (res == -1) {
 				ast_autochan_destroy(autochan);
+				iter = ast_channel_iterator_destroy(iter);
 				goto exit;
 			} else if (res == -2) {
 				res = 0;
 				ast_autochan_destroy(autochan);
+				iter = ast_channel_iterator_destroy(iter);
 				goto exit;
 			} else if (res > 1 && spec) {
 				struct ast_channel *next;
@@ -1005,6 +1011,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 					}
 				}
 			} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
+				iter = ast_channel_iterator_destroy(iter);
 				goto exit;
 			}
 		}
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 0f192acb64..84f075751f 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1426,9 +1426,9 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena
 				ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
 				break;
 			} else {
-				ao2_unlock(q);
 				ao2_ref(member, -1);
 				ao2_iterator_destroy(&mem_iter);
+				ao2_unlock(q);
 				ast_debug(4, "%s is available.\n", member->membername);
 				return 0;
 			}
@@ -4560,24 +4560,24 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 		AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
 		if (!tmp) {
 			ao2_ref(cur, -1);
-			ao2_unlock(qe->parent);
 			ao2_iterator_destroy(&memi);
+			ao2_unlock(qe->parent);
 			goto out;
 		}
 		if (!datastore) {
 			if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
+				callattempt_free(tmp);
 				ao2_ref(cur, -1);
-				ao2_unlock(qe->parent);
 				ao2_iterator_destroy(&memi);
-				callattempt_free(tmp);
+				ao2_unlock(qe->parent);
 				goto out;
 			}
 			datastore->inheritance = DATASTORE_INHERIT_FOREVER;
 			if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
+				callattempt_free(tmp);
 				ao2_ref(cur, -1);
-				ao2_unlock(&qe->parent);
 				ao2_iterator_destroy(&memi);
-				callattempt_free(tmp);
+				ao2_unlock(&qe->parent);
 				goto out;
 			}
 			datastore->data = dialed_interfaces;
@@ -4601,6 +4601,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 
 		if (di) {
 			callattempt_free(tmp);
+			ao2_ref(cur, -1);
 			continue;
 		}
 
@@ -4610,10 +4611,10 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 		 * it won't call one that has already been called. */
 		if (strncasecmp(cur->interface, "Local/", 6)) {
 			if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
+				callattempt_free(tmp);
 				ao2_ref(cur, -1);
-				ao2_unlock(qe->parent);
 				ao2_iterator_destroy(&memi);
-				callattempt_free(tmp);
+				ao2_unlock(qe->parent);
 				goto out;
 			}
 			strcpy(di->interface, cur->interface);
@@ -6623,9 +6624,10 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char *
 
 	if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
 		int buflen = 0, count = 0;
-		struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
+		struct ao2_iterator mem_iter;
 
 		ao2_lock(q);
+		mem_iter = ao2_iterator_init(q->members, 0);
 		while ((m = ao2_iterator_next(&mem_iter))) {
 			/* strcat() is always faster than printf() */
 			if (count++) {
@@ -7148,7 +7150,9 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena
 static int clear_stats(const char *queuename)
 {
 	struct call_queue *q;
-	struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
+	struct ao2_iterator queue_iter;
+
+	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
 		ao2_lock(q);
 		if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
@@ -7237,8 +7241,8 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
 		}
 	}
 
-	queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
 	ao2_lock(queues);
+	queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
 	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
 		float sl;
 		struct call_queue *realtime_queue = NULL;
@@ -7967,11 +7971,11 @@ static char *complete_queue_remove_member(const char *line, const char *word, in
 		while ((m = ao2_iterator_next(&mem_iter))) {
 			if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
 				char *tmp;
-				ao2_unlock(q);
 				tmp = ast_strdup(m->interface);
 				ao2_ref(m, -1);
-				queue_t_unref(q, "Done with iterator, returning interface name");
 				ao2_iterator_destroy(&mem_iter);
+				ao2_unlock(q);
+				queue_t_unref(q, "Done with iterator, returning interface name");
 				ao2_iterator_destroy(&queue_iter);
 				return tmp;
 			}
@@ -8524,6 +8528,7 @@ static void queues_data_provider_get_helper(const struct ast_data_search *search
 
 		ao2_ref(member, -1);
 	}
+	ao2_iterator_destroy(&im);
 
 	/* include the callers inside the result. */
 	if (queue->head) {
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 2255801c07..9d442d5a09 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -2636,6 +2636,7 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
 			sin.sin_addr.s_addr = peercnt->addr;
 			if (a->argc == 5 && (!strcasecmp(a->argv[4], ast_inet_ntoa(sin.sin_addr)))) {
 					ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
+					ao2_ref(peercnt, -1);
 					found = 1;
 					break;
 			} else {
@@ -6680,8 +6681,7 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
 
 	ast_cli(a->fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C","Codec Pref");
 	i = ao2_iterator_init(users, 0);
-	for (user = ao2_iterator_next(&i); user; 
-		user_unref(user), user = ao2_iterator_next(&i)) {
+	for (; (user = ao2_iterator_next(&i)); user_unref(user)) {
 		if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0))
 			continue;
 
@@ -6769,8 +6769,7 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
 		ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
 
 	i = ao2_iterator_init(peers, 0);
-	for (peer = ao2_iterator_next(&i); peer;
-		peer_unref(peer), peer = ao2_iterator_next(&i)) {
+	for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
 		char nm[20];
 		char status[20];
 		int retstatus;
@@ -7093,7 +7092,7 @@ static int manager_iax2_show_peer_list(struct mansession *s, const struct messag
 
 
 	i = ao2_iterator_init(peers, 0);
-	for (peer = ao2_iterator_next(&i); peer; peer_unref(peer), peer = ao2_iterator_next(&i)) {
+	for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
 		encmethods_to_str(peer->encmethods, encmethods);
 		astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext);
 		if (!ast_strlen_zero(peer->username)) {
@@ -7676,8 +7675,8 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
 		return res;
 	}
 	/* Search the userlist for a compatible entry, and fill in the rest */
-	i = ao2_iterator_init(users, 0);
 	ast_sockaddr_from_sin(&addr, sin);
+	i = ao2_iterator_init(users, 0);
 	while ((user = ao2_iterator_next(&i))) {
 		if ((ast_strlen_zero(iaxs[callno]->username) ||				/* No username specified */
 			!strcmp(iaxs[callno]->username, user->name))	/* Or this username specified */
@@ -14681,10 +14680,9 @@ static int users_data_provider_get(const struct ast_data_search *search,
 	char *pstr = "";
 
 	i = ao2_iterator_init(users, 0);
-	while ((user = ao2_iterator_next(&i))) {
+	for (; (user = ao2_iterator_next(&i)); user_unref(user)) {
 		data_user = ast_data_add_node(data_root, "user");
 		if (!data_user) {
-			user_unref(user);
 			continue;
 		}
 
@@ -14733,8 +14731,6 @@ static int users_data_provider_get(const struct ast_data_search *search,
 		}
 		ast_data_add_str(data_user, "codec-preferences", pstr);
 
-		user_unref(user);
-
 		if (!ast_data_search_match(search, data_user)) {
 			ast_data_remove_node(data_root, data_user);
 		}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index a5634fe947..73a4b74001 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -17639,8 +17639,8 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
 			while ((pi = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
 				ao2_lock(pi);
 				if (name && regexec(&regexbuf, pi->name, 0, NULL, 0)) {
-					sip_unref_peer(pi, "toss iterator peer ptr before continue");
 					ao2_unlock(pi);
+					sip_unref_peer(pi, "toss iterator peer ptr before continue");
 					continue;
 				};
 				if (ast_test_flag(&pi->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
@@ -31103,6 +31103,8 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 		/* transfer mode */
 		enum_node = ast_data_add_node(data_peer, "allowtransfer");
 		if (!enum_node) {
+			ao2_unlock(peer);
+			ao2_ref(peer, -1);
 			continue;
 		}
 		ast_data_add_str(enum_node, "text", transfermode2str(peer->allowtransfer));
@@ -31142,6 +31144,8 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 		/* amaflags */
 		enum_node = ast_data_add_node(data_peer, "amaflags");
 		if (!enum_node) {
+			ao2_unlock(peer);
+			ao2_ref(peer, -1);
 			continue;
 		}
 		ast_data_add_int(enum_node, "value", peer->amaflags);
@@ -31150,6 +31154,8 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 		/* sip options */
 		data_sip_options = ast_data_add_node(data_peer, "sipoptions");
 		if (!data_sip_options) {
+			ao2_unlock(peer);
+			ao2_ref(peer, -1);
 			continue;
 		}
 		for (x = 0 ; x < ARRAY_LEN(sip_options); x++) {
@@ -31159,6 +31165,8 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 		/* callingpres */
 		enum_node = ast_data_add_node(data_peer, "callingpres");
 		if (!enum_node) {
+			ao2_unlock(peer);
+			ao2_ref(peer, -1);
 			continue;
 		}
 		ast_data_add_int(enum_node, "value", peer->callingpres);
diff --git a/include/asterisk/indications.h b/include/asterisk/indications.h
index 13422d92bc..b02be1fdf1 100644
--- a/include/asterisk/indications.h
+++ b/include/asterisk/indications.h
@@ -176,7 +176,8 @@ int ast_tone_zone_count(void);
 /*!
  * \brief Get an iterator for the available tone zones
  *
- * Use ao2_iterator_next() to iterate the tone zones.
+ * \note Use ao2_iterator_next() to iterate the tone zones.
+ * \note Use ao2_iterator_destroy() to clean up.
  *
  * \return an initialized iterator
  */
diff --git a/main/indications.c b/main/indications.c
index ef98407f5c..b07de4bc4a 100644
--- a/main/indications.c
+++ b/main/indications.c
@@ -658,6 +658,7 @@ static char *complete_country(struct ast_cli_args *a)
 			break;
 		}
 	}
+	ao2_iterator_destroy(&i);
 
 	return res;
 }
@@ -835,6 +836,7 @@ static char *handle_cli_indication_show(struct ast_cli_entry *e, int cmd, struct
 			ast_tone_zone_unlock(tz);
 			tz = ast_tone_zone_unref(tz);
 		}
+		ao2_iterator_destroy(&iter);
 		return CLI_SUCCESS;
 	}
 
diff --git a/main/pbx.c b/main/pbx.c
index 204eb88416..e565c480fd 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -7605,6 +7605,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
 			AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
 		}
 	}
+	ao2_iterator_destroy(&i);
 
 	/* save the old table and list */
 	oldtable = contexts_table;
diff --git a/main/taskprocessor.c b/main/taskprocessor.c
index e0d7e5b94a..782a344516 100644
--- a/main/taskprocessor.c
+++ b/main/taskprocessor.c
@@ -173,6 +173,7 @@ static char *tps_taskprocessor_tab_complete(struct ast_taskprocessor *p, struct
 		}
 		ao2_ref(p, -1);
 	}
+	ao2_iterator_destroy(&i);
 	return name;
 }
 
@@ -266,6 +267,7 @@ static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 		ast_cli(a->fd, "\n%24s   %17ld %12ld %12ld", name, processed, qsize, maxqsize);
 		ao2_ref(p, -1);
 	}
+	ao2_iterator_destroy(&i);
 	tcount = ao2_container_count(tps_singletons); 
 	ast_cli(a->fd, "\n\t+---------------------+-----------------+------------+-------------+\n\t%d taskprocessors\n\n", tcount);
 	return CLI_SUCCESS;	
diff --git a/res/res_odbc.c b/res/res_odbc.c
index 1770bb3032..463bf9fdb4 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -911,7 +911,7 @@ static int load_odbc_config(void)
 
 static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
+	struct ao2_iterator aoi;
 	struct odbc_class *class;
 	struct odbc_obj *current;
 	int length = 0;
@@ -930,6 +930,7 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c
 		if (a->pos != 2)
 			return NULL;
 		length = strlen(a->word);
+		aoi = ao2_iterator_init(class_container, 0);
 		while ((class = ao2_iterator_next(&aoi))) {
 			if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
 				ret = ast_strdup(class->name);
@@ -1722,12 +1723,14 @@ static int data_odbc_provider_handler(const struct ast_data_search *search,
 
 			ao2_ref(current, -1);
 		}
+		ao2_iterator_destroy(&aoi2);
 		ao2_ref(class, -1);
 
 		if (!ast_data_search_match(search, data_odbc_class)) {
 			ast_data_remove_node(root, data_odbc_class);
 		}
 	}
+	ao2_iterator_destroy(&aoi);
 	return 0;
 }
 
diff --git a/res/res_srtp.c b/res/res_srtp.c
index a232314fae..a22a02089b 100644
--- a/res/res_srtp.c
+++ b/res/res_srtp.c
@@ -322,7 +322,7 @@ static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rt
 	int retry = 0;
 	struct ast_rtp_instance_stats stats = {0,};
 
-	tryagain:
+tryagain:
 
 	for (i = 0; i < 2; i++) {
 		res = rtcp ? srtp_unprotect_rtcp(srtp->session, buf, len) : srtp_unprotect(srtp->session, buf, len);
@@ -348,38 +348,42 @@ static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rt
 		if (srtp->session) {
 			struct ast_srtp_policy *policy;
 			struct ao2_iterator it;
-			int policies_count = 0;
-			
+			int policies_count;
+
 			// dealloc first
 			ast_log(LOG_WARNING, "SRTP destroy before re-create\n");
 			srtp_dealloc(srtp->session);
-			
+
 			// get the count
 			policies_count = ao2_container_count(srtp->policies);
-			
+
 			// get the first to build up
 			it = ao2_iterator_init(srtp->policies, 0);
 			policy = ao2_iterator_next(&it);
 
 			ast_log(LOG_WARNING, "SRTP try to re-create\n");
-        		if (srtp_create(&srtp->session, &policy->sp) == err_status_ok) {
-				ast_log(LOG_WARNING, "SRTP re-created with first policy\n");
-				
-				// unref first element
-				ao2_t_ref(policy, -1, "Unreffing first policy for re-creating srtp session");
-				
-				// if we have more than one policy, add them afterwards	
-				if (policies_count > 1) {
-					ast_log(LOG_WARNING, "Add all the other %d policies\n", policies_count-1);
-					while ((policy = ao2_iterator_next(&it))) {
-						srtp_add_stream(srtp->session, &policy->sp);
-						ao2_t_ref(policy, -1, "Unreffing n-th policy for re-creating srtp session");
+			if (policy) {
+				if (srtp_create(&srtp->session, &policy->sp) == err_status_ok) {
+					ast_log(LOG_WARNING, "SRTP re-created with first policy\n");
+
+					// unref first element
+					ao2_t_ref(policy, -1, "Unreffing first policy for re-creating srtp session");
+
+					// if we have more than one policy, add them afterwards
+					if (policies_count > 1) {
+						ast_log(LOG_WARNING, "Add all the other %d policies\n",
+							policies_count - 1);
+						while ((policy = ao2_iterator_next(&it))) {
+							srtp_add_stream(srtp->session, &policy->sp);
+							ao2_t_ref(policy, -1, "Unreffing n-th policy for re-creating srtp session");
+						}
 					}
+
+					retry++;
+					ao2_iterator_destroy(&it);
+					goto tryagain;
 				}
-				
-				retry++;
-				ao2_iterator_destroy(&it);
-				goto tryagain;
+				ao2_t_ref(policy, -1, "Unreffing first policy after srtp_create failed");
 			}
 			ao2_iterator_destroy(&it);
 		}
diff --git a/res/snmp/agent.c b/res/snmp/agent.c
index 153106e0dc..71f02134f5 100644
--- a/res/snmp/agent.c
+++ b/res/snmp/agent.c
@@ -703,6 +703,7 @@ static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *lengt
 			tz = ast_tone_zone_unref(tz);
 			long_ret++;
 		}
+		ao2_iterator_destroy(&i);
 
 		return (u_char *) &long_ret;
 	}
@@ -743,6 +744,7 @@ static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t
 		tz = ast_tone_zone_unref(tz);
 		i--;
 	}
+	ao2_iterator_destroy(&iter);
 
 	if (tz == NULL) {
 		return NULL;
@@ -750,24 +752,27 @@ static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t
 
 	switch (vp->magic) {
 	case ASTINDINDEX:
+		ast_tone_zone_unref(tz);
 		long_ret = name[*length - 1];
 		return (u_char *)&long_ret;
 	case ASTINDCOUNTRY:
 		ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
-		tz = ast_tone_zone_unref(tz);
+		ast_tone_zone_unref(tz);
 		*var_len = strlen(ret_buf);
 		return (u_char *) ret_buf;
 	case ASTINDALIAS:
 		/* No longer exists */
+		ast_tone_zone_unref(tz);
 		return NULL;
 	case ASTINDDESCRIPTION:
 		ast_tone_zone_lock(tz);
 		ast_copy_string(ret_buf, tz->description, sizeof(ret_buf));
 		ast_tone_zone_unlock(tz);
-		tz = ast_tone_zone_unref(tz);
+		ast_tone_zone_unref(tz);
 		*var_len = strlen(ret_buf);
 		return (u_char *) ret_buf;
 	default:
+		ast_tone_zone_unref(tz);
 		break;
 	}
 	return NULL;
-- 
GitLab