From 2131743e3bea9b7d923c02508ed10683209085e1 Mon Sep 17 00:00:00 2001
From: Nikolay Shirokovskiy <nshirokovskiy@tarantool.org>
Date: Thu, 4 Jul 2024 14:03:46 +0300
Subject: [PATCH] fiber: phohibit fiber self join

In this case join will just hang. Instead let's raise an error in case
of Lua API and panic in case of C API.

Closes #10196

NO_DOC=minor

(cherry picked from commit 1e1bf36dbceafce625a8ce7e54951892cc8e2fa0)
---
 .../unreleased/gh-10196-fix-fiber-self-join-hang.md  |  3 +++
 src/lib/core/fiber.c                                 |  3 +++
 src/lib/core/fiber.h                                 |  1 +
 src/lua/fiber.c                                      |  2 ++
 test/app-luatest/fiber_test.lua                      | 12 ++++++++++++
 5 files changed, 21 insertions(+)
 create mode 100644 changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md

diff --git a/changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md b/changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md
new file mode 100644
index 0000000000..872c3f4531
--- /dev/null
+++ b/changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md
@@ -0,0 +1,3 @@
+## bugfix/core
+
+* Fixed hang on fiber self join (gh-10196).
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index cfc00ab741..b5782d9784 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -764,6 +764,9 @@ fiber_join_timeout(struct fiber *fiber, double timeout)
 	if ((fiber->flags & FIBER_JOIN_BEEN_INVOKED) != 0)
 		panic("join of a joined fiber detected");
 
+	if (fiber() == fiber)
+		panic("cannot join itself");
+
 	/* Prohibit joining the fiber and changing its joinability. */
 	fiber->flags |= FIBER_JOIN_BEEN_INVOKED;
 
diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h
index c1e67c3858..959d084fb0 100644
--- a/src/lib/core/fiber.h
+++ b/src/lib/core/fiber.h
@@ -366,6 +366,7 @@ fiber_set_joinable(struct fiber *fiber, bool yesno);
  *
  * @pre FIBER_IS_JOINABLE flag is set (panic if not).
  * @pre the fiber is not joined yet (panic if not).
+ * @pre the fiber is different from current (panic if not).
  *
  * \param f fiber to be woken up
  * \return fiber function ret code
diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index abe0c4efa4..3a922eaf8b 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -811,6 +811,8 @@ lbox_fiber_join(struct lua_State *L)
 
 	if (!(fiber->flags & FIBER_IS_JOINABLE))
 		luaL_error(L, "the fiber is not joinable");
+	if (fid == fiber()->fid)
+		luaL_error(L, "cannot join itself");
 	double timeout = TIMEOUT_INFINITY;
 	if (!lua_isnoneornil(L, 2)) {
 		if (!lua_isnumber(L, 2) ||
diff --git a/test/app-luatest/fiber_test.lua b/test/app-luatest/fiber_test.lua
index 4aa262617e..55fd621e26 100644
--- a/test/app-luatest/fiber_test.lua
+++ b/test/app-luatest/fiber_test.lua
@@ -81,3 +81,15 @@ g.test_gh_10187_no_memory_leak_on_dead_fiber_search = function()
     collectgarbage()
     t.assert_equals(weak_table.fiber, nil)
 end
+
+g.test_gh_10196_no_hang_on_self_join = function()
+    local f = fiber.new(function()
+        fiber.self():join()
+    end)
+    f:set_joinable(true)
+    f:wakeup()
+    fiber.yield()
+    local ok, res = f:join()
+    t.assert_not(ok)
+    t.assert_error_msg_contains('cannot join itself', box.error, res)
+end
-- 
GitLab