]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Fix assert-crash when destroying ioloop that has active context
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 3 Dec 2020 17:20:32 +0000 (19:20 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 21 Jul 2021 09:38:20 +0000 (12:38 +0300)
Normally the ioloop shouldn't have an active context at deinit, but it
seems to be possible in some situations. It's not really bad anyway, so
just allow it.

Fixes:
Panic: file ioloop.c: line 928 (io_loop_destroy): assertion failed: (ioloop->cur_ctx == NULL)

src/lib/ioloop.c
src/lib/test-ioloop.c

index 7ba0fb67233abcbb77dc82cf1612c397d71a4dba..ed90539e27feca0bf14a892ba6ed0ff4c2c41df9 100644 (file)
@@ -936,8 +936,8 @@ void io_loop_destroy(struct ioloop **_ioloop)
 
        if (ioloop->handler_context != NULL)
                io_loop_handler_deinit(ioloop);
-
-       i_assert(ioloop->cur_ctx == NULL);
+       if (ioloop->cur_ctx != NULL)
+               io_loop_context_unref(&ioloop->cur_ctx);
        i_free(ioloop);
 }
 
index 393291f60d0a235573cd409854661eccf88d28e0..b0ab89387cbb9aaad448485bf976d2da8748a582 100644 (file)
@@ -296,6 +296,35 @@ static void test_ioloop_pending_io(void)
        test_end();
 }
 
+static void test_ioloop_context_callback(struct ioloop_context *ctx)
+{
+       test_assert(io_loop_get_current_context(current_ioloop) == ctx);
+       io_loop_stop(current_ioloop);
+}
+
+static void test_ioloop_context(void)
+{
+       test_begin("ioloop context");
+       struct ioloop *ioloop = io_loop_create();
+       struct ioloop_context *ctx = io_loop_context_new(ioloop);
+
+       test_assert(io_loop_get_current_context(current_ioloop) == NULL);
+       io_loop_context_activate(ctx);
+       test_assert(io_loop_get_current_context(current_ioloop) == ctx);
+       struct timeout *to = timeout_add(0, test_ioloop_context_callback, ctx);
+
+       io_loop_run(ioloop);
+       test_assert(io_loop_get_current_context(current_ioloop) == NULL);
+       /* test that we don't crash at deinit if we leave the context active */
+       io_loop_context_activate(ctx);
+       test_assert(io_loop_get_current_context(current_ioloop) == ctx);
+
+       timeout_remove(&to);
+       io_loop_context_unref(&ctx);
+       io_loop_destroy(&ioloop);
+       test_end();
+}
+
 void test_ioloop(void)
 {
        test_ioloop_timeout();
@@ -304,4 +333,5 @@ void test_ioloop(void)
        test_ioloop_find_fd_conditions();
        test_ioloop_pending_io();
        test_ioloop_fd();
+       test_ioloop_context();
 }