Commit Diff


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
@@ -0,0 +1,3 @@
+## 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
@@ -367,21 +367,29 @@ static int
 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.
  */
@@ -389,7 +397,8 @@ static int
 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
@@ -0,0 +1,52 @@
+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