From 008658b349264538f76327f8d60f2db5451854ea Mon Sep 17 00:00:00 2001
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
Date: Tue, 12 Sep 2017 16:22:25 +0300
Subject: [PATCH] fiber: throw an error on too long fiber name

Throw error, if a new name for a fiber in Lua is too long.

Closes #2622
---
 extra/dist/tarantoolctl.in        |  2 +-
 src/box/lua/checkpoint_daemon.lua |  2 +-
 src/box/lua/net_box.lua           |  2 +-
 src/fiber.c                       |  6 ----
 src/fiber.h                       |  7 +++-
 src/lua/fiber.c                   | 29 ++++++++++++++--
 src/lua/socket.lua                |  4 +--
 test/app/fiber.result             | 56 +++++++++++++++++++++++++++++++
 test/app/fiber.test.lua           | 19 +++++++++++
 test/unit/fiber.cc                |  8 +++--
 test/unit/fiber.result            |  2 +-
 11 files changed, 118 insertions(+), 19 deletions(-)

diff --git a/extra/dist/tarantoolctl.in b/extra/dist/tarantoolctl.in
index 8ec54e241e..81b59d5491 100755
--- a/extra/dist/tarantoolctl.in
+++ b/extra/dist/tarantoolctl.in
@@ -415,7 +415,7 @@ local cat_formats = setmetatable({
 local orig_cfg = box.cfg
 
 local function wrapper_cfg(cfg)
-    fiber.name(instance_name)
+    fiber.name(instance_name, {truncate=true})
     log.info('Run console at %s', console_sock)
     console.listen(console_sock)
 
diff --git a/src/box/lua/checkpoint_daemon.lua b/src/box/lua/checkpoint_daemon.lua
index 686ea81035..0783c11a80 100644
--- a/src/box/lua/checkpoint_daemon.lua
+++ b/src/box/lua/checkpoint_daemon.lua
@@ -62,7 +62,7 @@ local function process(self)
 end
 
 local function daemon_fiber(self)
-    fiber.name(PREFIX)
+    fiber.name(PREFIX, {truncate = true})
     log.info("started")
 
     --
diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua
index 5cccc70723..17cdd9444e 100644
--- a/src/box/lua/net_box.lua
+++ b/src/box/lua/net_box.lua
@@ -192,7 +192,7 @@ local function create_transport(host, port, user, password, callback)
         set_state('connecting')
         fiber.create(function()
             worker_fiber = fiber_self()
-            fiber.name(string.format('%s:%s (net.box)', host, port))
+            fiber.name(string.format('%s:%s (net.box)', host, port), {truncate=true})
             local ok, err = pcall(protocol_sm)
             if not (ok or is_final_state[state]) then
                 set_state('error', E_UNKNOWN, err)
diff --git a/src/fiber.c b/src/fiber.c
index 298c7ab2f2..94157392b0 100644
--- a/src/fiber.c
+++ b/src/fiber.c
@@ -672,12 +672,6 @@ fiber_loop(MAYBE_UNUSED void *data)
 	}
 }
 
-/** Set fiber name.
- *
- * @param[in] name the new name of the fiber. Truncated to
- * FIBER_NAME_MAXLEN.
-*/
-
 void
 fiber_set_name(struct fiber *fiber, const char *name)
 {
diff --git a/src/fiber.h b/src/fiber.h
index 0d0930cf59..94b3f445cd 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -50,7 +50,7 @@
 extern "C" {
 #endif /* defined(__cplusplus) */
 
-enum { FIBER_NAME_MAX = 30 };
+enum { FIBER_NAME_MAX = 32 };
 
 enum {
 	/**
@@ -536,6 +536,11 @@ fiber_init(int (*fiber_invoke)(fiber_func f, va_list ap));
 void
 fiber_free(void);
 
+/**
+ * Set fiber name.
+ * @param fiber Fiber to set name for.
+ * @param name A new name of @a fiber.
+ */
 void
 fiber_set_name(struct fiber *fiber, const char *name);
 
diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index 81c3b70461..f6abfdbd2a 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -337,23 +337,46 @@ lbox_fiber_status(struct lua_State *L)
 	return 1;
 }
 
-/** Get or set fiber name.
+/**
+ * Get or set fiber name.
  * With no arguments, gets or sets the current fiber
  * name. It's also possible to get/set the name of
  * another fiber.
+ * Last argument can be a map with a single key:
+ * {truncate = boolean}. If truncate is true, then a new fiber
+ * name is truncated to a max possible fiber name length.
+ * If truncate is false (or was not specified), then too long
+ * new name raise error.
  */
 static int
 lbox_fiber_name(struct lua_State *L)
 {
 	struct fiber *f = fiber();
-	int name_index = 1;
+	int name_index;
+	int opts_index;
+	int top = lua_gettop(L);
 	if (lua_type(L, 1) == LUA_TUSERDATA) {
 		f = lbox_checkfiber(L, 1);
 		name_index = 2;
+		opts_index = 3;
+	} else {
+		name_index = 1;
+		opts_index = 2;
 	}
-	if (lua_gettop(L) == name_index) {
+	if (top == name_index || top == opts_index) {
 		/* Set name. */
 		const char *name = luaL_checkstring(L, name_index);
+		int name_len = strlen(name);
+		if (top == opts_index && lua_istable(L, opts_index)) {
+			lua_getfield(L, opts_index, "truncate");
+			/* Truncate the name if needed. */
+			if (lua_isboolean(L, -1) && lua_toboolean(L, -1) &&
+			    name_len > FIBER_NAME_MAX)
+				name_len = FIBER_NAME_MAX;
+			lua_pop(L, 1);
+		}
+		if (name_len > FIBER_NAME_MAX)
+			luaL_error(L, "Fiber name is too long");
 		fiber_set_name(f, name);
 		return 0;
 	} else {
diff --git a/src/lua/socket.lua b/src/lua/socket.lua
index 2e263f5f01..10c6f8fb1d 100644
--- a/src/lua/socket.lua
+++ b/src/lua/socket.lua
@@ -993,7 +993,7 @@ local function tcp_connect(host, port, timeout)
 end
 
 local function tcp_server_handler(server, sc, from)
-    fiber.name(format("%s/%s:%s", server.name, from.host, from.port))
+    fiber.name(format("%s/%s:%s", server.name, from.host, from.port), {truncate = true})
     local status, message = pcall(server.handler, sc, from)
     sc:shutdown()
     sc:close()
@@ -1003,7 +1003,7 @@ local function tcp_server_handler(server, sc, from)
 end
 
 local function tcp_server_loop(server, s, addr)
-    fiber.name(format("%s/%s:%s", server.name, addr.host, addr.port))
+    fiber.name(format("%s/%s:%s", server.name, addr.host, addr.port), {truncate = true})
     log.info("started")
     while socket_readable(s) do
         local sc, from = socket_accept(s)
diff --git a/test/app/fiber.result b/test/app/fiber.result
index d42a08df99..699bf3d740 100644
--- a/test/app/fiber.result
+++ b/test/app/fiber.result
@@ -964,6 +964,62 @@ session_type = nil
 fiber = nil
 ---
 ...
+--
+-- gh-2622 fiber.name() truncates new name
+--
+fiber = require('fiber')
+---
+...
+long_name = string.rep('a', 300)
+---
+...
+fiber.name()
+---
+- 'console/unix/:'
+...
+fiber.name('new_name')
+---
+...
+fiber.name(long_name)
+---
+- error: Fiber name is too long
+...
+fiber.name()
+---
+- new_name
+...
+fiber.name(long_name, {truncate = true})
+---
+...
+fiber.name()
+---
+- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+...
+f = fiber.self()
+---
+...
+fiber.name(f)
+---
+- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+...
+fiber.name(f, 'new_name')
+---
+...
+fiber.name(f, long_name)
+---
+- error: Fiber name is too long
+...
+fiber.name(f)
+---
+- new_name
+...
+fiber.name(f, long_name, {truncate = true})
+---
+...
+fiber.name(f)
+---
+- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+...
 test_run:cmd("clear filter")
 ---
 - true
diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua
index 1d36b6c80e..e9da622d2d 100644
--- a/test/app/fiber.test.lua
+++ b/test/app/fiber.test.lua
@@ -399,4 +399,23 @@ session_type = nil
 
 fiber = nil
 
+--
+-- gh-2622 fiber.name() truncates new name
+--
+fiber = require('fiber')
+long_name = string.rep('a', 300)
+fiber.name()
+fiber.name('new_name')
+fiber.name(long_name)
+fiber.name()
+fiber.name(long_name, {truncate = true})
+fiber.name()
+f = fiber.self()
+fiber.name(f)
+fiber.name(f, 'new_name')
+fiber.name(f, long_name)
+fiber.name(f)
+fiber.name(f, long_name, {truncate = true})
+fiber.name(f)
+
 test_run:cmd("clear filter")
diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc
index 790141178d..3e9c479c58 100644
--- a/test/unit/fiber.cc
+++ b/test/unit/fiber.cc
@@ -151,9 +151,11 @@ fiber_name_test()
 
 	note("set new fiber name: %s.\n", fiber_name(fiber()));
 
-	fiber_set_name(fiber(), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-		       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-		       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+	const char *long_name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\
+		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+	fiber_set_name(fiber(), long_name);
 
 	note("fiber name is truncated: %s.\n", fiber_name(fiber()));
 	footer();
diff --git a/test/unit/fiber.result b/test/unit/fiber.result
index 4c09c14462..4f7108ffcc 100644
--- a/test/unit/fiber.result
+++ b/test/unit/fiber.result
@@ -5,7 +5,7 @@ SystemError Failed to allocate 42 bytes in allocator for exception: Cannot alloc
 
 # set new fiber name: Horace.
 
-# fiber name is truncated: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
+# fiber name is truncated: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
 
 	*** fiber_name_test: done ***
 	*** fiber_join_test ***
-- 
GitLab