Mercurial > dovecot > core-2.2
changeset 19533:06825c099fa1
dict: Avoid a crash when dict connection is already closed when async lookup finishes.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Mon, 04 Jan 2016 20:51:34 +0200 |
parents | 4cd83ea1a420 |
children | 25e892203e2b |
files | src/dict/dict-commands.c src/dict/dict-connection.c src/dict/dict-connection.h |
diffstat | 3 files changed, 28 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dict/dict-commands.c Mon Jan 04 13:12:18 2016 -0500 +++ b/src/dict/dict-commands.c Mon Jan 04 20:51:34 2016 +0200 @@ -75,7 +75,7 @@ o_stream_nsend_str(conn->output, cmd->reply); dict_connection_cmd_remove(cmd); } - dict_connection_unref(conn); + dict_connection_unref_safe(conn); } static void
--- a/src/dict/dict-connection.c Mon Jan 04 13:12:18 2016 -0500 +++ b/src/dict/dict-connection.c Mon Jan 04 20:51:34 2016 +0200 @@ -238,8 +238,33 @@ return FALSE; } +static void dict_connection_unref_safe_callback(struct dict_connection *conn) +{ + if (conn->to_unref != NULL) + timeout_remove(&conn->to_unref); + (void)dict_connection_unref(conn); +} + +void dict_connection_unref_safe(struct dict_connection *conn) +{ + if (conn->refcount == 1) { + /* delayed unref to make sure we don't try to call + dict_deinit() from a dict-callback. that's too much trouble + for each dict driver to be able to handle. */ + if (conn->to_unref == NULL) { + conn->to_unref = timeout_add_short(0, + dict_connection_unref_safe_callback, conn); + } + } else { + (void)dict_connection_unref(conn); + } +} + void dict_connection_destroy(struct dict_connection *conn) { + i_assert(!conn->destroyed); + i_assert(conn->to_unref == NULL); + conn->destroyed = TRUE; DLLIST_REMOVE(&dict_connections, conn);
--- a/src/dict/dict-connection.h Mon Jan 04 13:12:18 2016 -0500 +++ b/src/dict/dict-connection.h Mon Jan 04 20:51:34 2016 +0200 @@ -24,6 +24,7 @@ struct istream *input; struct ostream *output; struct timeout *to_input; + struct timeout *to_unref; /* There are only a few transactions per client, so keeping them in array is fast enough */ @@ -38,6 +39,7 @@ void dict_connection_ref(struct dict_connection *conn); bool dict_connection_unref(struct dict_connection *conn); +void dict_connection_unref_safe(struct dict_connection *conn); void dict_connection_continue_input(struct dict_connection *conn);