From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com Subject: [PATCH 2/2] coio: fix getaddrinfo assertion on 0 timeout Date: Fri, 17 May 2019 18:21:24 +0300 [thread overview] Message-ID: <58bcc084409063f1ee093e436cc06c8f79a47e16.1558106383.git.v.shpilevoy@tarantool.org> (raw) In-Reply-To: <cover.1558106383.git.v.shpilevoy@tarantool.org> Background. Coio provides a way to schedule arbitrary tasks execution in worker threads. A task consists of a function to execute, and a custom destructor. To push a task the function coio_task_post(task, timeout) was used. When the function returns 0, a caller can obtain a result and should free the task manually. But the trick is that if timeout was 0, the task was posted in a detached state. A detached task frees its memory automatically despite coio_task_post() result, and does not even yield. Such a task object can't be accessed and so much the more freed manually. coio_getaddrinfo() used coio_task_post() and freed the task when the latter function returned 0. It led to double free when timeout was set 0. The bug was introduced here 800cec7311955e1d9dfd2b9f881712d002090f3a in an attempt to do not yield in say_logrotate, because it is not fiber-safe. Now there are two functions: coio_task_execute(task, timeout), which never detaches a task completed successfully, and coio_task_post(task), which posts a task in a detached state. Closes #4209 --- src/lib/core/coio_task.c | 22 +++++++++++----------- src/lib/core/coio_task.h | 17 ++++++++++++++--- src/lib/core/say.c | 2 +- test/unit/coio.cc | 18 ++++++++++++++++++ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/lib/core/coio_task.c b/src/lib/core/coio_task.c index d8095eef3..908b336ed 100644 --- a/src/lib/core/coio_task.c +++ b/src/lib/core/coio_task.c @@ -227,22 +227,22 @@ coio_task_destroy(struct coio_task *task) diag_destroy(&task->diag); } +void +coio_task_post(struct coio_task *task) +{ + assert(task->base.type == EIO_CUSTOM); + assert(task->fiber == fiber()); + eio_submit(&task->base); + task->fiber = NULL; +} + int -coio_task_post(struct coio_task *task, double timeout) +coio_task_execute(struct coio_task *task, double timeout) { assert(task->base.type == EIO_CUSTOM); assert(task->fiber == fiber()); eio_submit(&task->base); - if (timeout == 0) { - /* - * This is a special case: - * we don't wait any response from the task - * and just perform just asynchronous post. - */ - task->fiber = NULL; - return 0; - } fiber_yield_timeout(timeout); if (!task->complete) { /* timed out or cancelled. */ @@ -409,7 +409,7 @@ coio_getaddrinfo(const char *host, const char *port, } /* Post coio task */ - if (coio_task_post(&task->base, timeout) != 0) + if (coio_task_execute(&task->base, timeout) != 0) return -1; /* timed out or cancelled */ /* Task finished */ diff --git a/src/lib/core/coio_task.h b/src/lib/core/coio_task.h index bb981f0b0..e81e10cca 100644 --- a/src/lib/core/coio_task.h +++ b/src/lib/core/coio_task.h @@ -63,7 +63,11 @@ typedef int (*coio_task_cb)(struct coio_task *task); /* like eio_req */ */ struct coio_task { struct eio_req base; /* eio_task - must be first */ - /** The calling fiber. */ + /** + * The calling fiber. When set to NULL, the task is + * detached - its resources are freed eventually, and such + * a task should not be accessed after detachment. + */ struct fiber *fiber; /** Callbacks. */ union { @@ -102,7 +106,7 @@ void coio_task_destroy(struct coio_task *task); /** - * Post coio task to EIO thread pool. + * Execute a coio task in a worker thread. * * @param task coio task. * @param timeout timeout in seconds. @@ -114,7 +118,14 @@ coio_task_destroy(struct coio_task *task); * callback. */ int -coio_task_post(struct coio_task *task, double timeout); +coio_task_execute(struct coio_task *task, double timeout); + +/** + * Post a task in detached state. Its result can't be obtained, + * and destructor is called after completion. + */ +void +coio_task_post(struct coio_task *task); /** \cond public */ diff --git a/src/lib/core/say.c b/src/lib/core/say.c index 24963cf82..0b2cf2c34 100644 --- a/src/lib/core/say.c +++ b/src/lib/core/say.c @@ -343,7 +343,7 @@ say_logrotate(struct ev_loop *loop, struct ev_signal *w, int revents) coio_task_create(&task->base, logrotate_cb, logrotate_cleanup_cb); task->log = log; task->loop = loop(); - coio_task_post(&task->base, 0); + coio_task_post(&task->base); } errno = saved_errno; } diff --git a/test/unit/coio.cc b/test/unit/coio.cc index a2439bf46..75054d45d 100644 --- a/test/unit/coio.cc +++ b/test/unit/coio.cc @@ -80,6 +80,24 @@ test_getaddrinfo(void) int rc = coio_getaddrinfo(host, port, NULL, &i, 1); is(rc, 0, "getaddringo"); freeaddrinfo(i); + + /* + * gh-4209: 0 timeout should not be a special value and + * detach a task. Before a fix it led to segfault + * sometimes. The cycle below runs getaddrinfo multiple + * times to increase segfault probability. + */ + for (int j = 0; j < 5; ++j) { + if (coio_getaddrinfo(host, port, NULL, &i, 0) == 0 && i != NULL) + freeaddrinfo(i); + /* + * Skip one event loop to check, that the coio + * task destructor will not free the memory second + * time. + */ + fiber_sleep(0); + } + check_plan(); footer(); } -- 2.20.1 (Apple Git-117)
next prev parent reply other threads:[~2019-05-17 15:21 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-05-17 15:21 [PATCH 0/2] netbox connect timeout assertion Vladislav Shpilevoy 2019-05-17 15:21 ` [PATCH 1/2] coio: make hints in coio_getaddrinfo optional Vladislav Shpilevoy 2019-05-17 15:21 ` Vladislav Shpilevoy [this message] 2019-05-20 14:53 ` [PATCH 0/2] netbox connect timeout assertion Vladimir Davydov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=58bcc084409063f1ee093e436cc06c8f79a47e16.1558106383.git.v.shpilevoy@tarantool.org \ --to=v.shpilevoy@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=vdavydov.dev@gmail.com \ --subject='Re: [PATCH 2/2] coio: fix getaddrinfo assertion on 0 timeout' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox