From 81c43d92f665bd696cb7bfbcfbbfb978fd0857dd Mon Sep 17 00:00:00 2001
From: Wenpeng Song <wenpeng.song@iopsys.eu>
Date: Fri, 8 Mar 2024 09:58:36 +0000
Subject: [PATCH] Workaround for reference count correction

There is a remaining channel when ref>2 or Asterisk may crash when ref<2 in ast_hangup().
---
 main/bridge_channel.c |  4 +---
 main/channel.c        | 11 +++++++++++
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 56c81843ab..207d408bdd 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -2974,10 +2974,8 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
 		ast_debug(1, "Channel %s simulating UNHOLD for bridge end.\n",
 			ast_channel_name(bridge_channel->chan));
 		ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
-		// leaving channel with Ref > 2 cause it is not destroyed during hangup
-		while (2 < ao2_ref(bridge_channel->chan, 0))
-			ao2_ref(bridge_channel->chan, -1);
 	}
+	ast_debug(3, "channel %s, Refs: %d\n", ast_channel_name(bridge_channel->chan),ao2_ref(bridge_channel->chan, 0));
 
 	/* Complete any partial DTMF digit before exiting the bridge. */
 	if (ast_channel_sending_dtmf_digit(bridge_channel->chan)) {
diff --git a/main/channel.c b/main/channel.c
index eabfe2f0f6..245337aed5 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -2548,6 +2548,17 @@ void ast_hangup(struct ast_channel *chan)
 
 	ast_debug(1, "Channel %p '%s' hanging up.  Refs: %d\n", chan, ast_channel_name(chan),
 		ao2_ref(chan, 0));
+	// leaving channel with Ref > 2 cause it is not destroyed during hangup, Ref < 2 cause crash during hangup
+	// race condition during REFER on chan_voicemngr_attended_call_transfer,
+	// Ref = 1 during the hangup when this ref decrease happened before the unref from chan_voicemngr_attended_call_transfer
+	if (2 != ao2_ref(chan, 0)){
+		ast_log(LOG_NOTICE, "ref count mismatched during hangup\n");
+		while (2 < ao2_ref(chan, 0))
+			ao2_ref(chan, -1);
+		while (2 > ao2_ref(chan, 0)) // Add ref back in case of race condition happened.
+			ao2_ref(chan, +1);
+		ast_debug(3, "channel %s, Refs: %d\n", ast_channel_name(chan),ao2_ref(chan, 0));
+	}
 
 	ast_autoservice_stop(chan);
 
-- 
GitLab