From be71e70a91a3c857652a8b037dac7adf9d0fcdd1 Mon Sep 17 00:00:00 2001
From: SmallJoker <SmallJoker@users.noreply.github.com>
Date: Mon, 27 Apr 2020 07:02:39 +0200
Subject: Script: Enforce type checks if not nil (#9748)

* Script: Enforce type checks if not nil
---
 src/script/common/c_content.cpp    | 76 ++++++++++++++++++++++----------------
 src/script/common/c_converter.cpp  | 32 ++++++++--------
 src/script/common/c_converter.h    |  6 +--
 src/script/lua_api/l_inventory.cpp | 14 ++++---
 4 files changed, 72 insertions(+), 56 deletions(-)

(limited to 'src/script')

diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 25dada757..8335fccb5 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -102,7 +102,8 @@ void read_item_definition(lua_State* L, int index,
 	lua_pop(L, 1);
 
 	lua_getfield(L, index, "sounds");
-	if(lua_istable(L, -1)){
+	if (!lua_isnil(L, -1)) {
+		luaL_checktype(L, -1, LUA_TTABLE);
 		lua_getfield(L, -1, "place");
 		read_soundspec(L, -1, def.sound_place);
 		lua_pop(L, 1);
@@ -182,9 +183,11 @@ void read_object_properties(lua_State *L, int index,
 {
 	if(index < 0)
 		index = lua_gettop(L) + 1 + index;
-	if(!lua_istable(L, index))
+	if (lua_isnil(L, index))
 		return;
 
+	luaL_checktype(L, -1, LUA_TTABLE);
+
 	int hp_max = 0;
 	if (getintfield(L, -1, "hp_max", hp_max)) {
 		prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
@@ -1027,13 +1030,15 @@ void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
 {
 	if(index < 0)
 		index = lua_gettop(L) + 1 + index;
-	if(lua_isnil(L, index)){
-	} else if(lua_istable(L, index)){
+	if (lua_isnil(L, index))
+		return;
+
+	if (lua_istable(L, index)) {
 		getstringfield(L, index, "name", spec.name);
 		getfloatfield(L, index, "gain", spec.gain);
 		getfloatfield(L, index, "fade", spec.fade);
 		getfloatfield(L, index, "pitch", spec.pitch);
-	} else if(lua_isstring(L, index)){
+	} else if (lua_isstring(L, index)) {
 		spec.name = lua_tostring(L, index);
 	}
 }
@@ -1055,9 +1060,13 @@ void push_soundspec(lua_State *L, const SimpleSoundSpec &spec)
 NodeBox read_nodebox(lua_State *L, int index)
 {
 	NodeBox nodebox;
-	if(lua_istable(L, -1)){
-		nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
-				ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
+	if (lua_isnil(L, -1))
+		return nodebox;
+
+	luaL_checktype(L, -1, LUA_TTABLE);
+
+	nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
+			ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
 
 #define NODEBOXREAD(n, s){ \
 		lua_getfield(L, index, (s)); \
@@ -1067,30 +1076,30 @@ NodeBox read_nodebox(lua_State *L, int index)
 	}
 
 #define NODEBOXREADVEC(n, s) \
-		lua_getfield(L, index, (s)); \
-		if (lua_istable(L, -1)) \
-			(n) = read_aabb3f_vector(L, -1, BS); \
-		lua_pop(L, 1);
+	lua_getfield(L, index, (s)); \
+	if (lua_istable(L, -1)) \
+		(n) = read_aabb3f_vector(L, -1, BS); \
+	lua_pop(L, 1);
+
+	NODEBOXREADVEC(nodebox.fixed, "fixed");
+	NODEBOXREAD(nodebox.wall_top, "wall_top");
+	NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
+	NODEBOXREAD(nodebox.wall_side, "wall_side");
+	NODEBOXREADVEC(nodebox.connect_top, "connect_top");
+	NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom");
+	NODEBOXREADVEC(nodebox.connect_front, "connect_front");
+	NODEBOXREADVEC(nodebox.connect_left, "connect_left");
+	NODEBOXREADVEC(nodebox.connect_back, "connect_back");
+	NODEBOXREADVEC(nodebox.connect_right, "connect_right");
+	NODEBOXREADVEC(nodebox.disconnected_top, "disconnected_top");
+	NODEBOXREADVEC(nodebox.disconnected_bottom, "disconnected_bottom");
+	NODEBOXREADVEC(nodebox.disconnected_front, "disconnected_front");
+	NODEBOXREADVEC(nodebox.disconnected_left, "disconnected_left");
+	NODEBOXREADVEC(nodebox.disconnected_back, "disconnected_back");
+	NODEBOXREADVEC(nodebox.disconnected_right, "disconnected_right");
+	NODEBOXREADVEC(nodebox.disconnected, "disconnected");
+	NODEBOXREADVEC(nodebox.disconnected_sides, "disconnected_sides");
 
-		NODEBOXREADVEC(nodebox.fixed, "fixed");
-		NODEBOXREAD(nodebox.wall_top, "wall_top");
-		NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
-		NODEBOXREAD(nodebox.wall_side, "wall_side");
-		NODEBOXREADVEC(nodebox.connect_top, "connect_top");
-		NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom");
-		NODEBOXREADVEC(nodebox.connect_front, "connect_front");
-		NODEBOXREADVEC(nodebox.connect_left, "connect_left");
-		NODEBOXREADVEC(nodebox.connect_back, "connect_back");
-		NODEBOXREADVEC(nodebox.connect_right, "connect_right");
-		NODEBOXREADVEC(nodebox.disconnected_top, "disconnected_top");
-		NODEBOXREADVEC(nodebox.disconnected_bottom, "disconnected_bottom");
-		NODEBOXREADVEC(nodebox.disconnected_front, "disconnected_front");
-		NODEBOXREADVEC(nodebox.disconnected_left, "disconnected_left");
-		NODEBOXREADVEC(nodebox.disconnected_back, "disconnected_back");
-		NODEBOXREADVEC(nodebox.disconnected_right, "disconnected_right");
-		NODEBOXREADVEC(nodebox.disconnected, "disconnected");
-		NODEBOXREADVEC(nodebox.disconnected_sides, "disconnected_sides");
-	}
 	return nodebox;
 }
 
@@ -1519,8 +1528,11 @@ void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask
 /******************************************************************************/
 void read_groups(lua_State *L, int index, ItemGroupList &result)
 {
-	if (!lua_istable(L,index))
+	if (lua_isnil(L, index))
 		return;
+
+	luaL_checktype(L, index, LUA_TTABLE);
+
 	result.clear();
 	lua_pushnil(L);
 	if (index < 0)
diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp
index 334af61c3..279d8b1a5 100644
--- a/src/script/common/c_converter.cpp
+++ b/src/script/common/c_converter.cpp
@@ -33,10 +33,9 @@ extern "C" {
 #define CHECK_TYPE(index, name, type) { \
 		int t = lua_type(L, (index)); \
 		if (t != (type)) { \
-			std::string traceback = script_get_backtrace(L); \
 			throw LuaError(std::string("Invalid ") + (name) + \
 				" (expected " + lua_typename(L, (type)) + \
-				" got " + lua_typename(L, t) + ").\n" + traceback); \
+				" got " + lua_typename(L, t) + ")."); \
 		} \
 	}
 #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
@@ -457,12 +456,22 @@ size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result
 	Table field getters
 */
 
+bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname)
+{
+	if (lua_isnil(L, index))
+		return false;
+
+	CHECK_TYPE(index, std::string("field \"") + fieldname + '"', type);
+	return true;
+}
+
 bool getstringfield(lua_State *L, int table,
 		const char *fieldname, std::string &result)
 {
 	lua_getfield(L, table, fieldname);
 	bool got = false;
-	if(lua_isstring(L, -1)){
+
+	if (check_field_or_nil(L, -1, LUA_TSTRING, fieldname)) {
 		size_t len = 0;
 		const char *ptr = lua_tolstring(L, -1, &len);
 		if (ptr) {
@@ -479,7 +488,8 @@ bool getfloatfield(lua_State *L, int table,
 {
 	lua_getfield(L, table, fieldname);
 	bool got = false;
-	if(lua_isnumber(L, -1)){
+
+	if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)) {
 		result = lua_tonumber(L, -1);
 		got = true;
 	}
@@ -492,7 +502,8 @@ bool getboolfield(lua_State *L, int table,
 {
 	lua_getfield(L, table, fieldname);
 	bool got = false;
-	if(lua_isboolean(L, -1)){
+
+	if (check_field_or_nil(L, -1, LUA_TBOOLEAN, fieldname)){
 		result = lua_toboolean(L, -1);
 		got = true;
 	}
@@ -511,17 +522,6 @@ size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
 	return num_strings_read;
 }
 
-std::string checkstringfield(lua_State *L, int table,
-		const char *fieldname)
-{
-	lua_getfield(L, table, fieldname);
-	CHECK_TYPE(-1, std::string("field \"") + fieldname + '"', LUA_TSTRING);
-	size_t len;
-	const char *s = lua_tolstring(L, -1, &len);
-	lua_pop(L, 1);
-	return std::string(s, len);
-}
-
 std::string getstringfield_default(lua_State *L, int table,
 		const char *fieldname, const std::string &default_)
 {
diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h
index 9620bf75a..a4a7079fd 100644
--- a/src/script/common/c_converter.h
+++ b/src/script/common/c_converter.h
@@ -45,13 +45,15 @@ float              getfloatfield_default(lua_State *L, int table,
 int                getintfield_default(lua_State *L, int table,
                              const char *fieldname, int default_);
 
+bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname);
+
 template<typename T>
 bool getintfield(lua_State *L, int table,
 		const char *fieldname, T &result)
 {
 	lua_getfield(L, table, fieldname);
 	bool got = false;
-	if (lua_isnumber(L, -1)){
+	if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)){
 		result = lua_tointeger(L, -1);
 		got = true;
 	}
@@ -87,8 +89,6 @@ bool               getboolfield(lua_State *L, int table,
                              const char *fieldname, bool &result);
 bool               getfloatfield(lua_State *L, int table,
                              const char *fieldname, float &result);
-std::string        checkstringfield(lua_State *L, int table,
-                             const char *fieldname);
 
 void               setstringfield(lua_State *L, int table,
                              const char *fieldname, const std::string &value);
diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp
index 6e7afa4a4..4c8977898 100644
--- a/src/script/lua_api/l_inventory.cpp
+++ b/src/script/lua_api/l_inventory.cpp
@@ -487,7 +487,9 @@ int ModApiInventory::l_get_inventory(lua_State *L)
 {
 	InventoryLocation loc;
 
-	std::string type = checkstringfield(L, 1, "type");
+	lua_getfield(L, 1, "type");
+	std::string type = luaL_checkstring(L, -1);
+	lua_pop(L, 1);
 
 	if(type == "node"){
 		MAP_LOCK_REQUIRED;
@@ -504,11 +506,13 @@ int ModApiInventory::l_get_inventory(lua_State *L)
 
 	NO_MAP_LOCK_REQUIRED;
 	if (type == "player") {
-		std::string name = checkstringfield(L, 1, "name");
-		loc.setPlayer(name);
+		lua_getfield(L, 1, "name");
+		loc.setPlayer(luaL_checkstring(L, -1));
+		lua_pop(L, 1);
 	} else if (type == "detached") {
-		std::string name = checkstringfield(L, 1, "name");
-		loc.setDetached(name);
+		lua_getfield(L, 1, "name");
+		loc.setDetached(luaL_checkstring(L, -1));
+		lua_pop(L, 1);
 	}
 
 	if (getServer(L)->getInventory(loc) != NULL)
-- 
cgit v1.2.3