From 4a6ffba12463845499c29ba0ed4a4a699bddda12 Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov@tarantool.org>
Date: Fri, 11 Aug 2023 18:15:35 +0300
Subject: [PATCH] box: fix box.iproto.override crash if used before box.cfg

The function can't be called on an unconfigured instance because it
needs IPROTO threads up and running. Let's raise an error to avoid
a crash.

Since we have two other places where we need to raise the same error
(box.session.su and box.__index), let's introduce the new code
ER_UNCONFIGURED for this error.

Closes #8975

NO_DOC=bug fix

(cherry picked from commit 4fd2686eb816eefc4f599677652e0c82b20c6644)
---
 .../gh-8975-box-iproto-override-without-cfg.md         |  4 ++++
 src/box/box.cc                                         | 10 ++++++++++
 src/box/box.h                                          |  6 ++++++
 src/box/errcode.h                                      |  8 ++++++++
 src/box/lua/iproto.c                                   |  2 ++
 src/box/lua/load_cfg.lua                               |  5 ++---
 src/box/lua/session.c                                  |  4 ++--
 .../iproto_request_handlers_overriding_test.lua        |  8 ++++++++
 test/box/error.result                                  |  1 +
 9 files changed, 43 insertions(+), 5 deletions(-)
 create mode 100644 changelogs/unreleased/gh-8975-box-iproto-override-without-cfg.md

diff --git a/changelogs/unreleased/gh-8975-box-iproto-override-without-cfg.md b/changelogs/unreleased/gh-8975-box-iproto-override-without-cfg.md
new file mode 100644
index 0000000000..0442810ab5
--- /dev/null
+++ b/changelogs/unreleased/gh-8975-box-iproto-override-without-cfg.md
@@ -0,0 +1,4 @@
+## bugfix/box
+
+* Fixed a crash when `box.iproto.override` was called with unconfigured box.
+  Now, an error is raised instead (gh-8975).
diff --git a/src/box/box.cc b/src/box/box.cc
index 9963b1a2d3..0d751332f5 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -4824,6 +4824,16 @@ box_is_configured(void)
 	return is_box_configured;
 }
 
+int
+box_check_configured(void)
+{
+	if (!is_box_configured) {
+		diag_set(ClientError, ER_UNCONFIGURED);
+		return -1;
+	}
+	return 0;
+}
+
 static void
 box_cfg_xc(void)
 {
diff --git a/src/box/box.h b/src/box/box.h
index f50e1de77b..5e10b41cee 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -119,6 +119,12 @@ box_cfg(void);
 bool
 box_is_configured(void);
 
+/**
+ * Return 0 if box has been configured, otherwise set diag and return -1.
+ */
+int
+box_check_configured(void);
+
 /** Check if the slice of main cord has expired. */
 int
 box_check_slice_slow(void);
diff --git a/src/box/errcode.h b/src/box/errcode.h
index 919353395a..97c7c09a29 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -319,6 +319,14 @@ struct errcode_record {
 	/*264 */_(ER_NIL_UUID,			"Nil UUID is reserved and can't be used in replication") \
 	/*265 */_(ER_WRONG_FUNCTION_OPTIONS,	"Wrong function options: %s") \
 	/*266 */_(ER_MISSING_SYSTEM_SPACES,	"Snapshot has no system spaces") \
+	/*267 */_(ER_UNUSED1,			"") \
+	/*268 */_(ER_UNUSED2,			"") \
+	/*269 */_(ER_UNUSED3,			"") \
+	/*270 */_(ER_UNUSED4,			"") \
+	/*271 */_(ER_UNUSED5,			"") \
+	/*272 */_(ER_UNUSED6,			"") \
+	/*273 */_(ER_UNUSED7,			"") \
+	/*274 */_(ER_UNCONFIGURED,		"Please call box.cfg{} first") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/lua/iproto.c b/src/box/lua/iproto.c
index 610ec9bdd6..a476ea1f18 100644
--- a/src/box/lua/iproto.c
+++ b/src/box/lua/iproto.c
@@ -313,6 +313,8 @@ lua_req_handler_destroy(void *ctx)
 static int
 lbox_iproto_override(struct lua_State *L)
 {
+	if (box_check_configured() != 0)
+		return luaT_error(L);
 	int n_args = lua_gettop(L);
 	if (n_args != 2)
 		return luaL_error(L, "Usage: "
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index ff6deb765c..5199ca18c6 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -983,9 +983,8 @@ for k, v in pairs(box) do
 end
 
 setmetatable(box, {
-    __index = function(table, index) -- luacheck: no unused args
-        error(debug.traceback("Please call box.cfg{} first"))
-        error("Please call box.cfg{} first")
+    __index = function()
+        box.error(box.error.UNCONFIGURED)
      end
 })
 
diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index a90027262b..4db8dcd4a4 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -166,8 +166,8 @@ lbox_session_effective_user(struct lua_State *L)
 static int
 lbox_session_su(struct lua_State *L)
 {
-	if (!box_is_configured())
-		luaL_error(L, "Please call box.cfg{} first");
+	if (box_check_configured() != 0)
+		luaT_error(L);
 	int top = lua_gettop(L);
 	if (top < 1)
 		luaL_error(L, "session.su(): bad arguments");
diff --git a/test/box-luatest/iproto_request_handlers_overriding_test.lua b/test/box-luatest/iproto_request_handlers_overriding_test.lua
index e034b463a7..18731e06aa 100644
--- a/test/box-luatest/iproto_request_handlers_overriding_test.lua
+++ b/test/box-luatest/iproto_request_handlers_overriding_test.lua
@@ -123,6 +123,14 @@ g.after_all(function(cg)
     cg.server:drop()
 end)
 
+-- Checks that `box.iproto.override` raises an error if called on
+-- an unconfigured instance (gh-8975).
+g.test_box_iproto_override_without_cfg = function()
+    t.assert_error_msg_equals('Please call box.cfg{} first',
+                              box.iproto.override, box.iproto.type.UNKNOWN,
+                              function() end)
+end
+
 -- Checks that `box.iproto.override` errors are handled correctly.
 g.test_box_iproto_override_errors = function(cg)
     cg.server:exec(function()
diff --git a/test/box/error.result b/test/box/error.result
index 68c20db041..4789fbfdda 100644
--- a/test/box/error.result
+++ b/test/box/error.result
@@ -484,6 +484,7 @@ t;
  |   264: box.error.NIL_UUID
  |   265: box.error.WRONG_FUNCTION_OPTIONS
  |   266: box.error.MISSING_SYSTEM_SPACES
+ |   274: box.error.UNCONFIGURED
  | ...
 
 test_run:cmd("setopt delimiter ''");
-- 
GitLab