commit - acbcc4c4f553ad9bd42ff63ba396e290bbf41898
commit + 1f534756d55a314dc0878a6275933627ae657263
blob - /dev/null
blob + 12186799eee77013ecba23de965acc61e83ad83e (mode 644)
--- /dev/null
+++ changelogs/unreleased/gh-10622-net-box-trigger-crash-on-self-delete.md
+## bugfix/lua/netbox
+
+* Fixed a crash when `net.box` triggers deleted themselves (gh-10622).
blob - da83f765821c68c82c5a07fa69ca407eb4768313
blob + 27a7d3e842174ef4dd241b27d64d32e75f7ac287
--- src/lua/trigger.c
+++ src/lua/trigger.c
luaT_trigger_list_run(struct lua_State *L)
{
struct rlist *trigger_list = luaT_check_trigger_list(L, 1);
- int top = lua_gettop(L);
- struct lbox_trigger *trigger;
- rlist_foreach_entry(trigger, trigger_list, base.link) {
- /* Only lbox_trigger is expected to be here. */
- assert(trigger->base.run == lbox_trigger_run);
- lua_rawgeti(L, LUA_REGISTRYINDEX, trigger->ref);
- for (int i = 2; i <= top; i++)
- lua_pushvalue(L, i);
- if (luaT_call(L, top - 1, 0) != 0)
- luaT_error(L);
- }
+ if (trigger_run(trigger_list, L) != 0)
+ luaT_error(L);
return 0;
}
/**
+ * Push event passed to `trigger_run` to Lua stack.
+ * Event must be a Lua stack, containing trigger list itself at the first
+ * place and all the arguments starting from the second place.
+ */
+static int
+luaT_trigger_list_push_event(struct lua_State *L, void *event)
+{
+ struct lua_State *args_L = (struct lua_State *)event;
+ int top = lua_gettop(args_L);
+ int argn = top - 1;
+ for (int i = 2; i <= top; i++)
+ lua_pushvalue(args_L, i);
+ lua_xmove(args_L, L, argn);
+ return argn;
+}
+
+/**
* Metamethod __call for trigger list.
* See description of lbox_trigger_reset for details.
*/
luaT_trigger_list_call(struct lua_State *L)
{
struct rlist *trigger_list = luaT_check_trigger_list(L, 1);
- return lbox_trigger_reset(L, 2, trigger_list, NULL, NULL);
+ return lbox_trigger_reset(L, 2, trigger_list,
+ luaT_trigger_list_push_event, NULL);
}
/**
blob - /dev/null
blob + 6ca22bb6471dac3fb7ff66bcdf79a49742f72365 (mode 644)
--- /dev/null
+++ test/box-luatest/gh_10622_net_box_trigger_crash_on_self_delete_test.lua
+local server = require('luatest.server')
+local t = require('luatest')
+
+local g = t.group()
+
+g.before_all(function()
+ g.server = server:new({alias = 'master'})
+ g.server:start()
+end)
+
+g.after_all(function()
+ g.server:stop()
+end)
+
+-- Reproducer from the issue
+g.test_net_box_trigger_crash_on_self_delete = function()
+ g.server:exec(function(uri)
+ local f = function(conn) conn:on_connect{name = 'test'} end
+ local net = require('net.box')
+ local c = net.connect(uri, {wait_connected = false})
+ c:on_connect{func = f, name = 'test'}
+ t.assert_not(c:is_connected())
+ t.assert(c:wait_connected(10))
+ end, {g.server.net_box_uri})
+end
+
+-- Check if Lua trigger list doesn't crash on self delete
+g.test_trigger_list_crash_on_self_delete = function()
+ g.server:exec(function()
+ local trigger_list = require('internal.trigger').new()
+ local function f()
+ trigger_list(nil, f)
+ end
+ trigger_list(f)
+ trigger_list:run()
+ end)
+end
+
+-- Check if Lua trigger list doesn't crash when one trigger
+-- clears the list
+g.test_trigger_list_crash_on_list_clear = function()
+ g.server:exec(function()
+ local trigger_list = require('internal.trigger').new()
+ local function f()
+ trigger_list(nil, nil, 't1')
+ trigger_list(nil, nil, 't2')
+ end
+ trigger_list(f, nil, 't1')
+ trigger_list(f, nil, 't2')
+ trigger_list:run()
+ end)
+end