From c068460b12be513d719a7b5ba9bfa0c334cf2b76 Mon Sep 17 00:00:00 2001 From: Terry Wilson Date: Wed, 2 May 2012 17:02:39 +0000 Subject: [PATCH] Don't leak a ref if out of memory and can't link the linkedid If the ao2_link fails, we are most likely out of memory and bad things are going to happen. Before those bad things happen, make sure to clean up the linkedid references. This patch also adds a comment explaining why linkedid can't be passed to both local channel allocations and combines two ao2_ref calls into 1. Review: https://reviewboard.asterisk.org/r/1895/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@365068 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_local.c | 3 +++ main/cel.c | 13 ++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/channels/chan_local.c b/channels/chan_local.c index eca253831f..f7d8f10393 100644 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -1112,6 +1112,9 @@ static struct ast_channel *local_new(struct local_pvt *p, int state, const char ama = p->owner->amaflags; else ama = 0; + + /* Make sure that the ;2 channel gets the same linkedid as ;1. You can't pass linkedid to both + * allocations since if linkedid isn't set, then each channel will generate its own linkedid. */ if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, tmp->linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) { if (tmp) { diff --git a/main/cel.c b/main/cel.c index fbcaa104b3..023fd571a9 100644 --- a/main/cel.c +++ b/main/cel.c @@ -377,10 +377,9 @@ void ast_cel_check_retire_linkedid(struct ast_channel *chan) return; } - /* We have a ref for each channel with this linkedid, the link and the above find, so if after - * unreffing for the channel we have a ref of 2, we're done. Unlink and report. */ - ao2_ref(lid, -1); - if (ao2_ref(lid, 0) == 2) { + /* We have a ref for each channel with this linkedid, the link and the above find, so if + * before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */ + if (ao2_ref(lid, -1) == 3) { ao2_unlink(linkedids, lid); ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL); } @@ -488,7 +487,11 @@ int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event return -1; } strcpy(lid, chan->linkedid); - ao2_link(linkedids, lid); + if (!ao2_link(linkedids, lid)) { + ao2_ref(lid, -1); + ast_mutex_unlock(&reload_lock); + return -1; + } /* Leave both the link and the alloc refs to show a count of 1 + the link */ } /* If we've found, go ahead and keep the ref to increment count of how many channels