JSON: Support consistent larger max. depth of 1024

This commit is contained in:
Lars Mueller
2024-10-14 15:46:25 +02:00
committed by Lars Müller
parent 4c419c4020
commit e2ea359925
4 changed files with 30 additions and 8 deletions

View File

@ -174,6 +174,21 @@ local function test_parse_json()
end end
unittests.register("test_parse_json", test_parse_json) unittests.register("test_parse_json", test_parse_json)
local function test_write_json()
-- deeply nested structures should be preserved
local leaf = 42
local data = leaf
for i = 1, 1000 do
data = {data}
end
local roundtripped = minetest.parse_json(minetest.write_json(data))
for i = 1, 1000 do
roundtripped = roundtripped[1]
end
assert(roundtripped == 42)
end
unittests.register("test_write_json", test_write_json)
local function test_game_info() local function test_game_info()
local info = minetest.get_game_info() local info = minetest.get_game_info()
local game_conf = Settings(info.path .. "/game.conf") local game_conf = Settings(info.path .. "/game.conf")

View File

@ -2149,11 +2149,11 @@ bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
} }
// Converts Lua table --> JSON // Converts Lua table --> JSON
void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion) void read_json_value(lua_State *L, Json::Value &root, int index, u16 max_depth)
{ {
if (recursion > 16) { if (max_depth == 0)
throw SerializationError("Maximum recursion depth exceeded"); throw SerializationError("depth exceeds MAX_JSON_DEPTH");
}
int type = lua_type(L, index); int type = lua_type(L, index);
if (type == LUA_TBOOLEAN) { if (type == LUA_TBOOLEAN) {
root = (bool) lua_toboolean(L, index); root = (bool) lua_toboolean(L, index);
@ -2164,11 +2164,13 @@ void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
const char *str = lua_tolstring(L, index, &len); const char *str = lua_tolstring(L, index, &len);
root = std::string(str, len); root = std::string(str, len);
} else if (type == LUA_TTABLE) { } else if (type == LUA_TTABLE) {
// Reserve two slots for key and value.
lua_checkstack(L, 2);
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, index)) { while (lua_next(L, index)) {
// Key is at -2 and value is at -1 // Key is at -2 and value is at -1
Json::Value value; Json::Value value;
read_json_value(L, value, lua_gettop(L), recursion + 1); read_json_value(L, value, lua_gettop(L), max_depth - 1);
Json::ValueType roottype = root.type(); Json::ValueType roottype = root.type();
int keytype = lua_type(L, -1); int keytype = lua_type(L, -1);

View File

@ -200,7 +200,7 @@ bool push_json_value (lua_State *L,
const Json::Value &value, const Json::Value &value,
int nullindex); int nullindex);
void read_json_value (lua_State *L, Json::Value &root, void read_json_value (lua_State *L, Json::Value &root,
int index, u8 recursion = 0); int index, u16 max_depth);
/*! /*!
* Pushes a Lua `pointed_thing` to the given Lua stack. * Pushes a Lua `pointed_thing` to the given Lua stack.

View File

@ -93,6 +93,10 @@ int ModApiUtil::l_get_us_time(lua_State *L)
return 1; return 1;
} }
// Maximum depth of a JSON object:
// Reading and writing should not overflow the Lua, C, or jsoncpp stacks.
constexpr static u16 MAX_JSON_DEPTH = 1024;
// parse_json(str[, nullvalue, return_error]) // parse_json(str[, nullvalue, return_error])
int ModApiUtil::l_parse_json(lua_State *L) int ModApiUtil::l_parse_json(lua_State *L)
{ {
@ -129,10 +133,11 @@ int ModApiUtil::l_parse_json(lua_State *L)
Json::Value root; Json::Value root;
{ {
Json::CharReaderBuilder builder; Json::CharReaderBuilder builder;
builder.settings_["stackLimit"] = MAX_JSON_DEPTH;
builder.settings_["collectComments"] = false; builder.settings_["collectComments"] = false;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
std::string errmsg; std::string errmsg;
if (!reader->parse(jsonstr.begin(), jsonstr.end(), &root, &errmsg)) if (!reader->parse(jsonstr.data(), jsonstr.data() + jsonstr.size(), &root, &errmsg))
return handle_error(errmsg.c_str()); return handle_error(errmsg.c_str());
} }
@ -155,7 +160,7 @@ int ModApiUtil::l_write_json(lua_State *L)
Json::Value root; Json::Value root;
try { try {
read_json_value(L, root, 1); read_json_value(L, root, 1, MAX_JSON_DEPTH);
} catch (SerializationError &e) { } catch (SerializationError &e) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, e.what()); lua_pushstring(L, e.what());