changeset 19531:21e41add1925

imap: Fixed crash in IDLE if DONE is received while sending large output to client. Fixes assert-crash with backtrace:
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 04 Jan 2016 12:40:39 -0500
parents 7104de520141
children 4cd83ea1a420
files src/imap/cmd-idle.c
diffstat 1 files changed, 10 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-idle.c	Mon Jan 04 12:02:12 2016 -0500
+++ b/src/imap/cmd-idle.c	Mon Jan 04 12:40:39 2016 -0500
@@ -136,13 +136,13 @@
 	idle_add_keepalive_timeout(ctx);
 }
 
-static void idle_sync_now(struct mailbox *box, struct cmd_idle_context *ctx)
+static bool idle_sync_now(struct mailbox *box, struct cmd_idle_context *ctx)
 {
 	i_assert(ctx->sync_ctx == NULL);
 
 	ctx->sync_pending = FALSE;
 	ctx->sync_ctx = imap_sync_init(ctx->client, box, 0, 0);
-	(void)cmd_idle_continue(ctx->cmd);
+	return cmd_idle_continue(ctx->cmd);
 }
 
 static void idle_callback(struct mailbox *box, struct cmd_idle_context *ctx)
@@ -153,7 +153,7 @@
 		ctx->sync_pending = TRUE;
 	else {
 		ctx->manual_cork = TRUE;
-		idle_sync_now(box, ctx);
+		(void)idle_sync_now(box, ctx);
 		if (client->disconnected)
 			client_destroy(client, NULL);
 	}
@@ -247,11 +247,11 @@
 
 	if (ctx->sync_pending) {
 		/* more changes occurred while we were sending changes to
-		   client */
-		idle_sync_now(client->mailbox, ctx);
-		/* NOTE: this recurses back to this function,
+		   client.
+
+		   NOTE: this recurses back to this function,
 		   so we return here instead of doing everything twice. */
-		return FALSE;
+		return idle_sync_now(client->mailbox, ctx);
 	}
 	if (ctx->to_hibernate == NULL)
 		idle_add_hibernate_timeout(ctx);
@@ -267,10 +267,11 @@
 		return TRUE;
 	}
 	if (client->io == NULL) {
-		/* input is pending */
+		/* input is pending. add the io back and mark the input as
+		   pending. we can't safely read more input immediately here. */
 		client->io = io_add_istream(client->input,
 					    idle_client_input, ctx);
-		(void)idle_client_input_more(ctx);
+		i_stream_set_input_pending(client->input, TRUE);
 	}
 	return FALSE;
 }