From: Timo Sirainen Date: Wed, 12 Aug 2020 08:58:07 +0000 (+0300) Subject: dict: Fix potential hang when iterating X-Git-Tag: 2.3.13~414 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=84b70b76a691fc8fe982ec9e93bab05f710c44c2;p=thirdparty%2Fdovecot%2Fcore.git dict: Fix potential hang when iterating Broken by 2937287a72cffa8c709c22ede838058d48b61778 --- diff --git a/src/dict/dict-commands.c b/src/dict/dict-commands.c index ef9912c29d..e7eaa1c339 100644 --- a/src/dict/dict-commands.c +++ b/src/dict/dict-commands.c @@ -238,6 +238,7 @@ static bool dict_connection_flush_if_full(struct dict_connection *conn) /* continue later when there's more space in output buffer */ o_stream_set_flush_pending(conn->conn.output, TRUE); + conn->iter_flush_pending = TRUE; return FALSE; } /* flushed everything, continue */ @@ -313,14 +314,21 @@ static void cmd_iterate_callback(void *context) dict_connection_ref(conn); o_stream_cork(conn->conn.output); - /* Uncork only if all the output has been finished. Some dict drivers - (e.g. dict-client) don't do any kind of buffering internally, so - this callback can write out only a single iteration. By leaving the - ostream corked it doesn't result in many tiny writes. */ + /* Don't uncork if we're just waiting for more input from the dict + driver. Some dict drivers (e.g. dict-client) don't do any kind of + buffering internally, so this callback can write out only a single + iteration. By leaving the ostream corked it doesn't result in many + tiny writes. However, we could be here also because the connection + output buffer is full already, in which case don't want to leave a + cork. */ + conn->iter_flush_pending = FALSE; cmd->uncork_pending = FALSE; if (dict_connection_cmd_output_more(cmd)) { /* NOTE: cmd may be freed now */ o_stream_uncork(conn->conn.output); + } else if (conn->iter_flush_pending) { + /* Don't leave the stream uncorked or we might get stuck. */ + o_stream_uncork(conn->conn.output); } else { /* It's possible that the command gets finished via some other code path. To make sure this doesn't cause hangs, uncork the diff --git a/src/dict/dict-connection.h b/src/dict/dict-connection.h index a07b64b7ad..d733e2ff86 100644 --- a/src/dict/dict-connection.h +++ b/src/dict/dict-connection.h @@ -29,6 +29,7 @@ struct dict_connection { ARRAY(struct dict_connection_cmd *) cmds; unsigned int async_id_counter; + bool iter_flush_pending; bool destroyed; };