From e744fa5f5bd323f68079600721bf1dffa55d3a53 Mon Sep 17 00:00:00 2001
From: Walter Doekes <walter+asterisk@wjd.nu>
Date: Fri, 9 Aug 2013 20:29:09 +0000
Subject: [PATCH] Don't leak frames when memory is full in autoservice_run.

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


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@396505 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 main/autoservice.c | 48 ++++++++++++++++++++++++++--------------------
 1 file changed, 27 insertions(+), 21 deletions(-)

diff --git a/main/autoservice.c b/main/autoservice.c
index 5b0c722efd..98f798b1ae 100644
--- a/main/autoservice.c
+++ b/main/autoservice.c
@@ -144,34 +144,40 @@ static void *autoservice_run(void *ign)
 			defer_frame = &hangup_frame;
 		} else if (ast_is_deferrable_frame(f)) {
 			defer_frame = f;
+		} else {
+			/* Can't defer. Discard and continue with next. */
+			ast_frfree(f);
+			continue;
 		}
 
-		if (defer_frame) {
-			for (i = 0; i < x; i++) {
-				struct ast_frame *dup_f;
+		for (i = 0; i < x; i++) {
+			struct ast_frame *dup_f;
 
-				if (mons[i] != chan) {
-					continue;
-				}
+			if (mons[i] != chan) {
+				continue;
+			}
 
-				if (defer_frame != f) {
-					if ((dup_f = ast_frdup(defer_frame))) {
-						AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
-					}
-				} else {
-					if ((dup_f = ast_frisolate(defer_frame))) {
-						if (dup_f != defer_frame) {
-							ast_frfree(defer_frame);
-						}
-						AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
-					}
+			if (!f) { /* defer_frame == &hangup_frame */
+				if ((dup_f = ast_frdup(defer_frame))) {
+					AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+				}
+			} else {
+				if ((dup_f = ast_frisolate(defer_frame))) {
+					AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+				}
+				if (dup_f != defer_frame) {
+					ast_frfree(defer_frame);
 				}
-
-				break;
 			}
-		} else if (f) {
-			ast_frfree(f);
+
+			break;
 		}
+		/* The ast_waitfor_n() call will only read frames from
+		 * the channels' file descriptors. If ast_waitfor_n()
+		 * returns non-NULL, then one of the channels in the
+		 * mons array must have triggered the return. It's
+		 * therefore impossible that we got here while (i >= x).
+		 * If we did, we'd need to ast_frfree(f) if (f). */
 	}
 
 	if (callid) {
-- 
GitLab