]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict: Avoid a crash when dict connection is already closed when async lookup finishes.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 4 Jan 2016 18:51:34 +0000 (20:51 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 4 Jan 2016 18:51:34 +0000 (20:51 +0200)
src/dict/dict-commands.c
src/dict/dict-connection.c
src/dict/dict-connection.h

index 2d87054c66dc6104a424bb0bc00f4e37f5a1d8b2..6f1ff337506d0809bab34012364ed89e5a336a3e 100644 (file)
@@ -75,7 +75,7 @@ static void dict_connection_cmds_flush(struct dict_connection *conn)
                o_stream_nsend_str(conn->output, cmd->reply);
                dict_connection_cmd_remove(cmd);
        }
-       dict_connection_unref(conn);
+       dict_connection_unref_safe(conn);
 }
 
 static void
index bcd868913e49fc012500a28e74374ff6659eee1f..9d856f0b2febaf12711d207d694ea2fc684d29a6 100644 (file)
@@ -238,8 +238,33 @@ bool dict_connection_unref(struct dict_connection *conn)
        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);
 
index 7ab6cef45fc2dfff0f4bc8f3c9cdd9e00399248e..87187993128f6c22472646170089ff527e01ccd1 100644 (file)
@@ -24,6 +24,7 @@ struct dict_connection {
        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_destroy(struct dict_connection *conn);
 
 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);