diff --git a/changelogs/unreleased/gh-6480-crash-if-box-cfg-listen-is-woken-up.md b/changelogs/unreleased/gh-6480-crash-if-box-cfg-listen-is-woken-up.md new file mode 100644 index 0000000000000000000000000000000000000000..cb5cb5bedd734da97042bef12dfd47939fe06cc7 --- /dev/null +++ b/changelogs/unreleased/gh-6480-crash-if-box-cfg-listen-is-woken-up.md @@ -0,0 +1,3 @@ +## bugfix/core + +* Fixed crash in case a fiber changing box.cfg.listen is woken up (gh-6480). diff --git a/src/box/iproto.cc b/src/box/iproto.cc index 436d743e2f98439d6a0538b7b945378f62b20f71..f68f0ea680cde03829533fb51c5766d68904524a 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -2955,21 +2955,29 @@ static inline int iproto_do_cfg(struct iproto_thread *iproto_thread, struct iproto_cfg_msg *msg) { msg->iproto_thread = iproto_thread; - if (cbus_call(&iproto_thread->net_pipe, &iproto_thread->tx_pipe, msg, - iproto_do_cfg_f, NULL, TIMEOUT_INFINITY) != 0) - return -1; - return 0; + bool prev = fiber_set_cancellable(false); + int rc = cbus_call(&iproto_thread->net_pipe, &iproto_thread->tx_pipe, + msg, iproto_do_cfg_f, NULL, TIMEOUT_INFINITY); + fiber_set_cancellable(prev); + return rc; } -static inline int +static inline void +iproto_do_cfg_crit(struct iproto_thread *iproto_thread, + struct iproto_cfg_msg *cfg_msg) +{ + int rc = iproto_do_cfg(iproto_thread, cfg_msg); + (void)rc; + assert(rc == 0); +} + +static inline void iproto_send_stop_msg(void) { struct iproto_cfg_msg cfg_msg; iproto_cfg_msg_create(&cfg_msg, IPROTO_CFG_STOP); for (int i = 0; i < iproto_threads_count; i++) - if (iproto_do_cfg(&iproto_threads[i], &cfg_msg) != 0) - return -1; - return 0; + iproto_do_cfg_crit(&iproto_threads[i], &cfg_msg); } static inline int @@ -2987,8 +2995,7 @@ iproto_send_listen_msg(struct evio_service *binary) int iproto_listen(const char *uri) { - if (iproto_send_stop_msg() != 0) - return -1; + iproto_send_stop_msg(); evio_service_stop(&tx_binary); if (uri == NULL) { tx_binary.addr_len = 0; @@ -3040,7 +3047,7 @@ iproto_thread_stats_get(struct iproto_stats *stats, int thread_id) iproto_cfg_msg_create(&cfg_msg, IPROTO_CFG_STAT); assert(thread_id >= 0 && thread_id < iproto_threads_count); cfg_msg.stats = stats; - iproto_do_cfg(&iproto_threads[thread_id], &cfg_msg); + iproto_do_cfg_crit(&iproto_threads[thread_id], &cfg_msg); stats->requests_in_progress = iproto_threads[thread_id].tx.requests_in_progress; } @@ -3066,8 +3073,7 @@ iproto_set_msg_max(int new_iproto_msg_max) iproto_cfg_msg_create(&cfg_msg, IPROTO_CFG_MSG_MAX); cfg_msg.iproto_msg_max = new_iproto_msg_max; for (int i = 0; i < iproto_threads_count; i++) { - if (iproto_do_cfg(&iproto_threads[i], &cfg_msg) != 0) - diag_raise(); + iproto_do_cfg_crit(&iproto_threads[i], &cfg_msg); cpipe_set_max_input(&iproto_threads[i].net_pipe, new_iproto_msg_max / 2); } diff --git a/test/box/gh-6480-crash-if-box-cfg-listen-is-woken-up.result b/test/box/gh-6480-crash-if-box-cfg-listen-is-woken-up.result new file mode 100644 index 0000000000000000000000000000000000000000..c942a5b5bb98a3bdd14fa0baf31a1e3a8128fe57 --- /dev/null +++ b/test/box/gh-6480-crash-if-box-cfg-listen-is-woken-up.result @@ -0,0 +1,25 @@ +test_run = require('test_run').new() +--- +... +fiber = require('fiber') +--- +... +f = fiber.create(function() box.stat.net() end) f:wakeup() +--- +... +old_listen = box.cfg.listen +--- +... +new_listen = old_listen .. "A" +--- +... +f = fiber.create(function() box.cfg{listen = new_listen} end) f:wakeup() +--- +... +test_run:wait_cond(function() return box.cfg.listen == new_listen end) +--- +- true +... +box.cfg{listen = old_listen} +--- +... diff --git a/test/box/gh-6480-crash-if-box-cfg-listen-is-woken-up.test.lua b/test/box/gh-6480-crash-if-box-cfg-listen-is-woken-up.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..4d521478801ccf788837787208815695cfa332ad --- /dev/null +++ b/test/box/gh-6480-crash-if-box-cfg-listen-is-woken-up.test.lua @@ -0,0 +1,10 @@ +test_run = require('test_run').new() +fiber = require('fiber') + +f = fiber.create(function() box.stat.net() end) f:wakeup() + +old_listen = box.cfg.listen +new_listen = old_listen .. "A" +f = fiber.create(function() box.cfg{listen = new_listen} end) f:wakeup() +test_run:wait_cond(function() return box.cfg.listen == new_listen end) +box.cfg{listen = old_listen}