* [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse @ 2021-04-28 10:22 Cyrill Gorcunov via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable Cyrill Gorcunov via Tarantool-patches ` (2 more replies) 0 siblings, 3 replies; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 10:22 UTC (permalink / raw) To: tml; +Cc: Vladislav Shpilevoy v2 (by Vlad): - Use explicit != 0 form for flag testing - in Lua's fiber:join() drop the test for FIBER_IS_JOINABLE flag since now we do the same on lower level - extend tests - provide changelog issue https://github.com/tarantool/tarantool/issues/6046 branch gorcunov/gh-6046-fiber-join-2 Cyrill Gorcunov (2): fiber: fiber_join -- drop redundat variable fiber: fiber_join -- don't crash on misuse .../unreleased/gh-6046-fiber-join-misuse.md | 6 ++++ src/lib/core/fiber.c | 12 +++++-- src/lua/fiber.c | 10 ++++-- test/app/fiber.result | 34 +++++++++++++++++++ test/app/fiber.test.lua | 12 +++++++ test/unit/fiber.cc | 7 ++++ 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/gh-6046-fiber-join-misuse.md base-commit: f44663ed75769a20095ff09f728e9b29f9319dc5 -- 2.30.2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable 2021-04-28 10:22 [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 10:22 ` Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse Cyrill Gorcunov via Tarantool-patches 2021-04-30 8:13 ` [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Kirill Yukhin via Tarantool-patches 2 siblings, 1 reply; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 10:22 UTC (permalink / raw) To: tml; +Cc: Vladislav Shpilevoy No need for additional variable here. In-scope-of #6046 Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- src/lib/core/fiber.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index cb6295171..a4b60e864 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -614,8 +614,7 @@ fiber_reschedule(void) int fiber_join(struct fiber *fiber) { - int rc = fiber_join_timeout(fiber, TIMEOUT_INFINITY); - return rc; + return fiber_join_timeout(fiber, TIMEOUT_INFINITY); } int -- 2.30.2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches 0 siblings, 0 replies; 14+ messages in thread From: Serge Petrenko via Tarantool-patches @ 2021-04-28 15:13 UTC (permalink / raw) To: Cyrill Gorcunov, tml; +Cc: Vladislav Shpilevoy 28.04.2021 13:22, Cyrill Gorcunov пишет: > No need for additional variable here. > > In-scope-of #6046 > > Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> > --- > src/lib/core/fiber.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c > index cb6295171..a4b60e864 100644 > --- a/src/lib/core/fiber.c > +++ b/src/lib/core/fiber.c > @@ -614,8 +614,7 @@ fiber_reschedule(void) > int > fiber_join(struct fiber *fiber) > { > - int rc = fiber_join_timeout(fiber, TIMEOUT_INFINITY); > - return rc; > + return fiber_join_timeout(fiber, TIMEOUT_INFINITY); > } > > int Thanks! LGTM -- Serge Petrenko ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 10:22 [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Cyrill Gorcunov via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 10:22 ` Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches 2021-04-28 21:16 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-30 8:13 ` [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Kirill Yukhin via Tarantool-patches 2 siblings, 2 replies; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 10:22 UTC (permalink / raw) To: tml; +Cc: Vladislav Shpilevoy In case if we call jiber_join() over the non joinable fiber we trigger an assert and crash execution (on debug build). On release build the asserts will be zapped and won't cause problems but there is an another one -- the target fiber will cause double fiber_reset() calls which in result cause to unregister_fid() with id = 0 (not causing crash but definitely out of intention) and we will drop stack protection which might be not ours anymore. Thus lets return error just like Lua interface does. Same time this allows us to relax Lua function a bit and leave flags testing on lower level. Fixes #6046 Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- .../unreleased/gh-6046-fiber-join-misuse.md | 6 ++++ src/lib/core/fiber.c | 9 ++++- src/lua/fiber.c | 10 ++++-- test/app/fiber.result | 34 +++++++++++++++++++ test/app/fiber.test.lua | 12 +++++++ test/unit/fiber.cc | 7 ++++ 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/gh-6046-fiber-join-misuse.md diff --git a/changelogs/unreleased/gh-6046-fiber-join-misuse.md b/changelogs/unreleased/gh-6046-fiber-join-misuse.md new file mode 100644 index 000000000..32c15566d --- /dev/null +++ b/changelogs/unreleased/gh-6046-fiber-join-misuse.md @@ -0,0 +1,6 @@ +## bugfix/core + +* Fixed lack of testing for non noinable fibers in `fiber_join()` call. + This could lead to unpredictable results. Note the issue affects C + level only, in Lua interface `fiber::join()`` the protection is + turned on already. diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index a4b60e864..c0580b101 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -620,7 +620,14 @@ fiber_join(struct fiber *fiber) int fiber_join_timeout(struct fiber *fiber, double timeout) { - assert(fiber->flags & FIBER_IS_JOINABLE); + if ((fiber->flags & FIBER_IS_JOINABLE) == 0) { + /* + * Don't change the error message, it is + * part of API. + */ + diag_set(IllegalParams, "the fiber is not joinable"); + return -1; + } if (! fiber_is_dead(fiber)) { bool exceeded = false; diff --git a/src/lua/fiber.c b/src/lua/fiber.c index 02ec3d158..0c8238cab 100644 --- a/src/lua/fiber.c +++ b/src/lua/fiber.c @@ -35,6 +35,8 @@ #include "backtrace.h" #include "tt_static.h" +#include "core/exception.h" + #include <lua.h> #include <lauxlib.h> #include <lualib.h> @@ -791,9 +793,11 @@ lbox_fiber_join(struct lua_State *L) int num_ret = 0; int coro_ref = 0; - if (!(fiber->flags & FIBER_IS_JOINABLE)) - luaL_error(L, "the fiber is not joinable"); - fiber_join(fiber); + if (fiber_join(fiber) != 0) { + e = diag_last_error(&fiber()->diag); + if (e->type == &type_IllegalParams) + luaL_error(L, e->errmsg); + } if (child_L != NULL) { coro_ref = lua_tointeger(child_L, -1); diff --git a/test/app/fiber.result b/test/app/fiber.result index 14c12b7cc..d3a245428 100644 --- a/test/app/fiber.result +++ b/test/app/fiber.result @@ -1150,6 +1150,40 @@ end, 10); - true - dead ... +-- gh-6046: make sure non joinable fiber fails +ch1 = fiber.channel(1); +--- +... +f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); +--- +... +f:set_joinable(false); +--- +... +_, errmsg = pcall(f.join, f); +--- +... +errmsg; +--- +- the fiber is not joinable +... +f:set_joinable(true); +--- +... +ch1:put(1); +--- +- true +... +ch1:close(); +--- +... +ch1 = nil; +--- +... +f:join(); +--- +- true +... -- test side fiber in transaction s = box.schema.space.create("test"); --- diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua index a471c83e9..430e4ae96 100644 --- a/test/app/fiber.test.lua +++ b/test/app/fiber.test.lua @@ -486,6 +486,18 @@ test_run:wait_cond(function() return status == 'dead', status end, 10); +-- gh-6046: make sure non joinable fiber fails +ch1 = fiber.channel(1); +f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); +f:set_joinable(false); +_, errmsg = pcall(f.join, f); +errmsg; +f:set_joinable(true); +ch1:put(1); +ch1:close(); +ch1 = nil; +f:join(); + -- test side fiber in transaction s = box.schema.space.create("test"); _ = s:create_index("prim", {parts={1, 'number'}}); diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc index a1e3ded87..13672dd31 100644 --- a/test/unit/fiber.cc +++ b/test/unit/fiber.cc @@ -96,6 +96,13 @@ fiber_join_test() header(); struct fiber *fiber = fiber_new_xc("join", noop_f); + /* gh-6046: crash on attempt to join non joinable */ + diag_clear(&fiber()->diag); + fiber_set_joinable(fiber, false); + if (fiber_join(fiber) != -1) + fail("fiber_join passed", ""); + if (diag_last_error(&fiber()->diag) == NULL) + fail("fiber_join has last error cleared", ""); fiber_set_joinable(fiber, true); fiber_wakeup(fiber); fiber_join(fiber); -- 2.30.2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches 2021-04-28 15:21 ` Cyrill Gorcunov via Tarantool-patches 2021-04-28 21:16 ` Vladislav Shpilevoy via Tarantool-patches 1 sibling, 1 reply; 14+ messages in thread From: Serge Petrenko via Tarantool-patches @ 2021-04-28 15:13 UTC (permalink / raw) To: Cyrill Gorcunov, tml; +Cc: Vladislav Shpilevoy Hi! Thanks for the patch! Please find 2 comments below. 28.04.2021 13:22, Cyrill Gorcunov пишет: > In case if we call jiber_join() over the non joinable fiber 1. typo: fiber_join. > we trigger an assert and crash execution (on debug build). > > On release build the asserts will be zapped and won't cause > problems but there is an another one -- the target fiber will > cause double fiber_reset() calls which in result cause to > unregister_fid() with id = 0 (not causing crash but definitely > out of intention) and we will drop stack protection which > might be not ours anymore. > > Thus lets return error just like Lua interface does. Same time > this allows us to relax Lua function a bit and leave flags testing > on lower level. > > Fixes #6046 > > Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> > --- > .../unreleased/gh-6046-fiber-join-misuse.md | 6 ++++ > src/lib/core/fiber.c | 9 ++++- > src/lua/fiber.c | 10 ++++-- > test/app/fiber.result | 34 +++++++++++++++++++ > test/app/fiber.test.lua | 12 +++++++ > test/unit/fiber.cc | 7 ++++ > 6 files changed, 74 insertions(+), 4 deletions(-) > create mode 100644 changelogs/unreleased/gh-6046-fiber-join-misuse.md > > diff --git a/changelogs/unreleased/gh-6046-fiber-join-misuse.md b/changelogs/unreleased/gh-6046-fiber-join-misuse.md > new file mode 100644 > index 000000000..32c15566d > --- /dev/null > +++ b/changelogs/unreleased/gh-6046-fiber-join-misuse.md > @@ -0,0 +1,6 @@ > +## bugfix/core > + > +* Fixed lack of testing for non noinable fibers in `fiber_join()` call. > + This could lead to unpredictable results. Note the issue affects C > + level only, in Lua interface `fiber::join()`` the protection is > + turned on already. > diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c > index a4b60e864..c0580b101 100644 > --- a/src/lib/core/fiber.c > +++ b/src/lib/core/fiber.c > @@ -620,7 +620,14 @@ fiber_join(struct fiber *fiber) > int > fiber_join_timeout(struct fiber *fiber, double timeout) > { > - assert(fiber->flags & FIBER_IS_JOINABLE); > + if ((fiber->flags & FIBER_IS_JOINABLE) == 0) { > + /* > + * Don't change the error message, it is > + * part of API. > + */ > + diag_set(IllegalParams, "the fiber is not joinable"); > + return -1; > + } > > if (! fiber_is_dead(fiber)) { > bool exceeded = false; > diff --git a/src/lua/fiber.c b/src/lua/fiber.c > index 02ec3d158..0c8238cab 100644 > --- a/src/lua/fiber.c > +++ b/src/lua/fiber.c > @@ -35,6 +35,8 @@ > #include "backtrace.h" > #include "tt_static.h" > > +#include "core/exception.h" > + > #include <lua.h> > #include <lauxlib.h> > #include <lualib.h> > @@ -791,9 +793,11 @@ lbox_fiber_join(struct lua_State *L) > int num_ret = 0; > int coro_ref = 0; > > - if (!(fiber->flags & FIBER_IS_JOINABLE)) > - luaL_error(L, "the fiber is not joinable"); > - fiber_join(fiber); > + if (fiber_join(fiber) != 0) { > + e = diag_last_error(&fiber()->diag); > + if (e->type == &type_IllegalParams) > + luaL_error(L, e->errmsg); > + } > > if (child_L != NULL) { > coro_ref = lua_tointeger(child_L, -1); > diff --git a/test/app/fiber.result b/test/app/fiber.result > index 14c12b7cc..d3a245428 100644 > --- a/test/app/fiber.result > +++ b/test/app/fiber.result > @@ -1150,6 +1150,40 @@ end, 10); > - true > - dead > ... > +-- gh-6046: make sure non joinable fiber fails > +ch1 = fiber.channel(1); > +--- > +... > +f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); 2. ch1:get() should be enough instead of the while loop. > +--- > +... > +f:set_joinable(false); > +--- > +... > +_, errmsg = pcall(f.join, f); > +--- > +... > +errmsg; > +--- > +- the fiber is not joinable > +... > +f:set_joinable(true); > +--- > +... > +ch1:put(1); > +--- > +- true > +... > +ch1:close(); > +--- > +... > +ch1 = nil; > +--- > +... > +f:join(); > +--- > +- true > +... > -- test side fiber in transaction > s = box.schema.space.create("test"); > --- > diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua > index a471c83e9..430e4ae96 100644 > --- a/test/app/fiber.test.lua > +++ b/test/app/fiber.test.lua > @@ -486,6 +486,18 @@ test_run:wait_cond(function() > return status == 'dead', status > end, 10); > > +-- gh-6046: make sure non joinable fiber fails > +ch1 = fiber.channel(1); > +f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); > +f:set_joinable(false); > +_, errmsg = pcall(f.join, f); > +errmsg; > +f:set_joinable(true); > +ch1:put(1); > +ch1:close(); > +ch1 = nil; > +f:join(); > + > -- test side fiber in transaction > s = box.schema.space.create("test"); > _ = s:create_index("prim", {parts={1, 'number'}}); > diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc > index a1e3ded87..13672dd31 100644 > --- a/test/unit/fiber.cc > +++ b/test/unit/fiber.cc > @@ -96,6 +96,13 @@ fiber_join_test() > header(); > > struct fiber *fiber = fiber_new_xc("join", noop_f); > + /* gh-6046: crash on attempt to join non joinable */ > + diag_clear(&fiber()->diag); > + fiber_set_joinable(fiber, false); > + if (fiber_join(fiber) != -1) > + fail("fiber_join passed", ""); > + if (diag_last_error(&fiber()->diag) == NULL) > + fail("fiber_join has last error cleared", ""); > fiber_set_joinable(fiber, true); > fiber_wakeup(fiber); > fiber_join(fiber); -- Serge Petrenko ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches @ 2021-04-28 15:21 ` Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:34 ` Serge Petrenko via Tarantool-patches 0 siblings, 1 reply; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 15:21 UTC (permalink / raw) To: Serge Petrenko; +Cc: tml, Vladislav Shpilevoy On Wed, Apr 28, 2021 at 06:13:30PM +0300, Serge Petrenko wrote: > Hi! Thanks for the patch! > Please find 2 comments below. Thanks! I've force pushed an update. --- test/app/fiber.result | 2 +- test/app/fiber.test.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/app/fiber.result b/test/app/fiber.result index d3a245428..b145302aa 100644 --- a/test/app/fiber.result +++ b/test/app/fiber.result @@ -1154,7 +1154,7 @@ end, 10); ch1 = fiber.channel(1); --- ... -f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); +f = fiber.new(function() ch1:get() end); --- ... f:set_joinable(false); diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua index 430e4ae96..9f25f7f9c 100644 --- a/test/app/fiber.test.lua +++ b/test/app/fiber.test.lua @@ -488,7 +488,7 @@ end, 10); -- gh-6046: make sure non joinable fiber fails ch1 = fiber.channel(1); -f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); +f = fiber.new(function() ch1:get() end); f:set_joinable(false); _, errmsg = pcall(f.join, f); errmsg; -- 2.30.2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 15:21 ` Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 15:34 ` Serge Petrenko via Tarantool-patches 0 siblings, 0 replies; 14+ messages in thread From: Serge Petrenko via Tarantool-patches @ 2021-04-28 15:34 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tml, Vladislav Shpilevoy 28.04.2021 18:21, Cyrill Gorcunov пишет: > On Wed, Apr 28, 2021 at 06:13:30PM +0300, Serge Petrenko wrote: >> Hi! Thanks for the patch! >> Please find 2 comments below. > Thanks! I've force pushed an update. > --- > test/app/fiber.result | 2 +- > test/app/fiber.test.lua | 2 +- > 2 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/test/app/fiber.result b/test/app/fiber.result > index d3a245428..b145302aa 100644 > --- a/test/app/fiber.result > +++ b/test/app/fiber.result > @@ -1154,7 +1154,7 @@ end, 10); > ch1 = fiber.channel(1); > --- > ... > -f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); > +f = fiber.new(function() ch1:get() end); > --- > ... > f:set_joinable(false); > diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua > index 430e4ae96..9f25f7f9c 100644 > --- a/test/app/fiber.test.lua > +++ b/test/app/fiber.test.lua > @@ -488,7 +488,7 @@ end, 10); > > -- gh-6046: make sure non joinable fiber fails > ch1 = fiber.channel(1); > -f = fiber.new(function() while ch1:is_empty() do fiber.sleep(0) end end); > +f = fiber.new(function() ch1:get() end); > f:set_joinable(false); > _, errmsg = pcall(f.join, f); > errmsg; Thanks! LGTM. -- Serge Petrenko ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches @ 2021-04-28 21:16 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-28 22:12 ` Cyrill Gorcunov via Tarantool-patches 1 sibling, 1 reply; 14+ messages in thread From: Vladislav Shpilevoy via Tarantool-patches @ 2021-04-28 21:16 UTC (permalink / raw) To: Cyrill Gorcunov, tml > diff --git a/src/lua/fiber.c b/src/lua/fiber.c > index 02ec3d158..0c8238cab 100644 > --- a/src/lua/fiber.c > +++ b/src/lua/fiber.c > @@ -791,9 +793,11 @@ lbox_fiber_join(struct lua_State *L) > int num_ret = 0; > int coro_ref = 0; > > - if (!(fiber->flags & FIBER_IS_JOINABLE)) > - luaL_error(L, "the fiber is not joinable"); > - fiber_join(fiber); > + if (fiber_join(fiber) != 0) { > + e = diag_last_error(&fiber()->diag); > + if (e->type == &type_IllegalParams) > + luaL_error(L, e->errmsg); After looking at this hunk I realized that it might be wrong to allow to call join on a non-joinable fiber. Firstly, you have no way to check why did join return -1: because it wasn't joinable or because this is what the fiber's function has returned. It is simply impossible in the public API (module.h). Secondly, fiber_join() is documented to always return the fiber's function result. I see it in module.h and on the site. Here the behaviour has kind of changed - it might return something even if the fiber didn't really end. This is especially bad if the fiber was using some resources which are freed right after the join. And doubly-bad if the user's function never fails, so fiber_join() result wasn't even checked in his code. Thirdly, this leads to inconsistent behaviour. In this example fiber.join does not raise an error - it returns false + error: fiber = require('fiber') do f = fiber.new(function() box.error('other error') end) f:set_joinable(true) end tarantool> f:join() --- - false - '[string "do..."]:2: box.error(): bad arguments' ... But when I change the error type, it raises the error: fiber = require('fiber') do f = fiber.new(function() box.lib.load() end) f:set_joinable(true) end tarantool> f:join() --- - error: Expects box.lib.load('name') but no name passed ... It didn't happen before your patch. The same problem exists for fiber_join_timeout(), but at least it is documented to be able to return before the fiber has joined. With that said, I think we must call panic() on an attempt to join a non-joinable fiber. For easier usage we might need to introduce fiber_join_ex(), which wouldn't mix its own fail and the fiber's function fail. But maybe not now since nobody really asked for that. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 21:16 ` Vladislav Shpilevoy via Tarantool-patches @ 2021-04-28 22:12 ` Cyrill Gorcunov via Tarantool-patches 2021-04-29 11:10 ` [Tarantool-patches] [PATCH v3 " Cyrill Gorcunov via Tarantool-patches 0 siblings, 1 reply; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-28 22:12 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tml On Wed, Apr 28, 2021 at 11:16:20PM +0200, Vladislav Shpilevoy wrote: > > diff --git a/src/lua/fiber.c b/src/lua/fiber.c > > index 02ec3d158..0c8238cab 100644 > > --- a/src/lua/fiber.c > > +++ b/src/lua/fiber.c > > @@ -791,9 +793,11 @@ lbox_fiber_join(struct lua_State *L) > > int num_ret = 0; > > int coro_ref = 0; > > > > - if (!(fiber->flags & FIBER_IS_JOINABLE)) > > - luaL_error(L, "the fiber is not joinable"); > > - fiber_join(fiber); > > + if (fiber_join(fiber) != 0) { > > + e = diag_last_error(&fiber()->diag); > > + if (e->type == &type_IllegalParams) > > + luaL_error(L, e->errmsg); > > After looking at this hunk I realized that it might be wrong to > allow to call join on a non-joinable fiber. Firstly, you have no > way to check why did join return -1: because it wasn't joinable > or because this is what the fiber's function has returned. It is > simply impossible in the public API (module.h). Not really. The error message returned actually a part of api. Before the patch if we call join() on non joinable fiber we have an error thrown with "the fiber is not joinable", right? So we keep it here intact. So in Lua interface we keep everything as it was (if only I'm not missing something obvious, sorry brain is almost off already). Now to the C level interface. When we call it with non joinable fiber without the patch it leads to some unpredictable results (for now, since in future we might reuse fiber_id = 0 or even something more wider) and a crash in *best* case. In worst case it is completely undeterminable behaviour and exiting with error (or even crash some user application if it is not ready for such change) is a way better than silent potential data corruption in memory. As to reason for exit -- we have two error codes here and diag last error will show it. So that user's module can fetch and figure out the reason. Or you mean something else? I'll reread your email tomorrow, as I said I might be brain off already :( side note: i figured out what you mean at the end of email... > Secondly, fiber_join() is documented to always return the > fiber's function result. I see it in module.h and on the site. > Here the behaviour has kind of changed - it might return something > even if the fiber didn't really end. This is especially bad if the > fiber was using some resources which are freed right after the join. > And doubly-bad if the user's function never fails, so fiber_join() > result wasn't even checked in his code. I see what you mean and this is api change indeed, but because of this nasty error we've to break the api I think (simply because not breaking api is a way worse). Obviously the C level of fibers API either not much used or all users are sane and do the test for joinability otherwise we would had a number of reports I think. > Thirdly, this leads to inconsistent behaviour. In this example > fiber.join does not raise an error - it returns false + error: > > fiber = require('fiber') > do > f = fiber.new(function() box.error('other error') end) > f:set_joinable(true) > end > > tarantool> f:join() > --- > - false > - '[string "do..."]:2: box.error(): bad arguments' > ... > > But when I change the error type, it raises the error: > > fiber = require('fiber') > do > f = fiber.new(function() box.lib.load() end) > f:set_joinable(true) > end > > tarantool> f:join() > --- > - error: Expects box.lib.load('name') but no name passed > ... > > It didn't happen before your patch. The same problem exists for > fiber_join_timeout(), but at least it is documented to be able to > return before the fiber has joined. So this comes from error type collision where before the patch we didn't have. And that is really a show stopper, agreed. > With that said, I think we must call panic() on an attempt to join > a non-joinable fiber. Another option is to enter endless loop with error message printed out? Say if ((fiber->flags & FIBER_IS_JOINABLE) == 0) { say_crit("Attempt to join nonjoinable fiber"); say_crit("Enters endless loop"); while (!(fiber->flags & FIBER_IS_JOINABLE)) fiber_yield(); } or something similar. At least a user will be able to do something? Don't get me wrong but panic is definitely the last big hammer kick when tarantool simply cant continue working. > For easier usage we might need to introduce fiber_join_ex(), which > wouldn't mix its own fail and the fiber's function fail. But maybe > not now since nobody really asked for that. Cyrill ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Tarantool-patches] [PATCH v3 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-28 22:12 ` Cyrill Gorcunov via Tarantool-patches @ 2021-04-29 11:10 ` Cyrill Gorcunov via Tarantool-patches 2021-04-29 19:37 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-29 21:10 ` Vladislav Shpilevoy via Tarantool-patches 0 siblings, 2 replies; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-29 11:10 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tml In case if we call fiber_join() over the non joinable fiber we trigger an assert and crash execution (on debug build). On release build the asserts will be zapped and won't cause problems but there is an another one -- the target fiber will cause double fiber_reset() calls which in result cause to unregister_fid() with id = 0 (not causing crash but definitely out of intention) and we will drop stack protection which might be not ours anymore. Since we're not allowed to break API on C level lets just panic early in case of such misuse, it is a way better than continue operating with potentially screwed data in memory. Fixes #6046 Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- issue https://github.com/tarantool/tarantool/issues/6046 branch gorcunov/gh-6046-fiber-join-3 changelogs/unreleased/gh-6046-fiber-join-misuse.md | 6 ++++++ src/lib/core/fiber.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/gh-6046-fiber-join-misuse.md diff --git a/changelogs/unreleased/gh-6046-fiber-join-misuse.md b/changelogs/unreleased/gh-6046-fiber-join-misuse.md new file mode 100644 index 000000000..32c15566d --- /dev/null +++ b/changelogs/unreleased/gh-6046-fiber-join-misuse.md @@ -0,0 +1,6 @@ +## bugfix/core + +* Fixed lack of testing for non noinable fibers in `fiber_join()` call. + This could lead to unpredictable results. Note the issue affects C + level only, in Lua interface `fiber::join()`` the protection is + turned on already. diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index a4b60e864..196dffe26 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -620,7 +620,8 @@ fiber_join(struct fiber *fiber) int fiber_join_timeout(struct fiber *fiber, double timeout) { - assert(fiber->flags & FIBER_IS_JOINABLE); + if ((fiber->flags & FIBER_IS_JOINABLE) == 0) + panic("the fiber is not joinable"); if (! fiber_is_dead(fiber)) { bool exceeded = false; -- 2.30.2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v3 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-29 11:10 ` [Tarantool-patches] [PATCH v3 " Cyrill Gorcunov via Tarantool-patches @ 2021-04-29 19:37 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-29 20:39 ` Cyrill Gorcunov via Tarantool-patches 2021-04-29 21:10 ` Vladislav Shpilevoy via Tarantool-patches 1 sibling, 1 reply; 14+ messages in thread From: Vladislav Shpilevoy via Tarantool-patches @ 2021-04-29 19:37 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tml Hi! Thanks for the patch! > diff --git a/changelogs/unreleased/gh-6046-fiber-join-misuse.md b/changelogs/unreleased/gh-6046-fiber-join-misuse.md > new file mode 100644 > index 000000000..32c15566d > --- /dev/null > +++ b/changelogs/unreleased/gh-6046-fiber-join-misuse.md > @@ -0,0 +1,6 @@ > +## bugfix/core > + > +* Fixed lack of testing for non noinable fibers in `fiber_join()` call. > + This could lead to unpredictable results. Note the issue affects C > + level only, in Lua interface `fiber::join()`` the protection is fiber::join() -> fiber:join() And `` -> ` in the end. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v3 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-29 19:37 ` Vladislav Shpilevoy via Tarantool-patches @ 2021-04-29 20:39 ` Cyrill Gorcunov via Tarantool-patches 0 siblings, 0 replies; 14+ messages in thread From: Cyrill Gorcunov via Tarantool-patches @ 2021-04-29 20:39 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tml On Thu, Apr 29, 2021 at 09:37:56PM +0200, Vladislav Shpilevoy wrote: > > +* Fixed lack of testing for non noinable fibers in `fiber_join()` call. > > + This could lead to unpredictable results. Note the issue affects C > > + level only, in Lua interface `fiber::join()`` the protection is > > fiber::join() -> fiber:join() > > And `` -> ` in the end. Force pushed an update. Thanks! branch gorcunov/gh-6046-fiber-join-3 --- changelogs/unreleased/gh-6046-fiber-join-misuse.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/unreleased/gh-6046-fiber-join-misuse.md b/changelogs/unreleased/gh-6046-fiber-join-misuse.md index 32c15566d..4515d96a8 100644 --- a/changelogs/unreleased/gh-6046-fiber-join-misuse.md +++ b/changelogs/unreleased/gh-6046-fiber-join-misuse.md @@ -2,5 +2,5 @@ * Fixed lack of testing for non noinable fibers in `fiber_join()` call. This could lead to unpredictable results. Note the issue affects C - level only, in Lua interface `fiber::join()`` the protection is + level only, in Lua interface `fiber:join()` the protection is turned on already. -- 2.30.2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v3 2/2] fiber: fiber_join -- don't crash on misuse 2021-04-29 11:10 ` [Tarantool-patches] [PATCH v3 " Cyrill Gorcunov via Tarantool-patches 2021-04-29 19:37 ` Vladislav Shpilevoy via Tarantool-patches @ 2021-04-29 21:10 ` Vladislav Shpilevoy via Tarantool-patches 1 sibling, 0 replies; 14+ messages in thread From: Vladislav Shpilevoy via Tarantool-patches @ 2021-04-29 21:10 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tml Thanks for the patch! LGTM. > issue https://github.com/tarantool/tarantool/issues/6046 > branch gorcunov/gh-6046-fiber-join-3 Kirill, use join-3, not join-2. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse 2021-04-28 10:22 [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Cyrill Gorcunov via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable Cyrill Gorcunov via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse Cyrill Gorcunov via Tarantool-patches @ 2021-04-30 8:13 ` Kirill Yukhin via Tarantool-patches 2 siblings, 0 replies; 14+ messages in thread From: Kirill Yukhin via Tarantool-patches @ 2021-04-30 8:13 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tml, Vladislav Shpilevoy Hello, On 28 апр 13:22, Cyrill Gorcunov wrote: > v2 (by Vlad): > - Use explicit != 0 form for flag testing > - in Lua's fiber:join() drop the test for FIBER_IS_JOINABLE > flag since now we do the same on lower level > - extend tests > - provide changelog > > issue https://github.com/tarantool/tarantool/issues/6046 > branch gorcunov/gh-6046-fiber-join-2 > > Cyrill Gorcunov (2): > fiber: fiber_join -- drop redundat variable > fiber: fiber_join -- don't crash on misuse > > .../unreleased/gh-6046-fiber-join-misuse.md | 6 ++++ > src/lib/core/fiber.c | 12 +++++-- > src/lua/fiber.c | 10 ++++-- > test/app/fiber.result | 34 +++++++++++++++++++ > test/app/fiber.test.lua | 12 +++++++ > test/unit/fiber.cc | 7 ++++ > 6 files changed, 75 insertions(+), 6 deletions(-) > create mode 100644 changelogs/unreleased/gh-6046-fiber-join-misuse.md I've checked your patchset into 2.8 and master. ALso, cherry-picked top patch to 2.7. -- Regards, Kirill Yukhin ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2021-04-30 8:13 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-04-28 10:22 [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Cyrill Gorcunov via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 1/2] fiber: fiber_join -- drop redundat variable Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches 2021-04-28 10:22 ` [Tarantool-patches] [PATCH v2 2/2] fiber: fiber_join -- don't crash on misuse Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:13 ` Serge Petrenko via Tarantool-patches 2021-04-28 15:21 ` Cyrill Gorcunov via Tarantool-patches 2021-04-28 15:34 ` Serge Petrenko via Tarantool-patches 2021-04-28 21:16 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-28 22:12 ` Cyrill Gorcunov via Tarantool-patches 2021-04-29 11:10 ` [Tarantool-patches] [PATCH v3 " Cyrill Gorcunov via Tarantool-patches 2021-04-29 19:37 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-29 20:39 ` Cyrill Gorcunov via Tarantool-patches 2021-04-29 21:10 ` Vladislav Shpilevoy via Tarantool-patches 2021-04-30 8:13 ` [Tarantool-patches] [PATCH v2 0/2] fiber: prevent fiber_join from misuse Kirill Yukhin via Tarantool-patches
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox