minetest
minetest copied to clipboard
Server crashes if generated chat message is too long
Minetest version
Minetest 5.2.0-dev-03e1f23a (Linux)
OS / Hardware
Operating system: Debian 10 CPU: Intel(R) Xeon(R) Gold 6140 CPU @ 2.30GHz
Summary
Server crashes if a generated chat message is too long with the following output:
2020-01-19 21:22:47: ERROR[Main]: ServerError: AsyncErr: ServerThread::run Lua: Runtime error from mod '' in callback on_chat_message(): String too long
2020-01-19 21:22:47: ERROR[Main]: stack traceback:
2020-01-19 21:22:47: ERROR[Main]: [C]: in function 'chat_send_player'
2020-01-19 21:22:47: ERROR[Main]: /usr/share/games/minetest/builtin/game/chat.lua:71: in function </usr/share/games/minetest/builtin/game/chat.lua:48>
2020-01-19 21:22:47: ERROR[Main]: /usr/share/games/minetest/builtin/game/register.lua:429: in function </usr/share/games/minetest/builtin/game/register.lua:413>
In this case, it was caused by /list_areas from the areas mod, on a server with 10k+ areas. Given the number of mods that might take user input, this could be a serious security risk.
Steps to reproduce
call minetest.chat_send_player with an extremely long chat message.
Should probably raise a warning + stack trace instead.
I'm interested into contributing a fix for this issue. Would it make sense to split the chat message into multiple messages and send one by one, or it is wise to cap at the maximum byte size and log a warning?
How about putting some ellipsis and log a warning? The limit is around 66 000 characters, that's definitely more than annoying already to see in chat. It should be up to the modder to split their output in pages, such as /list_areas 2, /list_areas 3 etc
in case anyone wants some lua code to patch their server to keep /profiler print from crashing their server, here's some:
local old_chat_send_player = minetest.chat_send_player
function minetest.chat_send_player(name, text)
while #text > 65000 do
local found_newline = false
for i = 65000, 1, -1 do
if text:sub(i, i) == "\n" then
old_chat_send_player(name, text:sub(1, i - 1))
text = text:sub(i + 1)
found_newline = true
break
end
end
if not found_newline then
old_chat_send_player(name, text:sub(1, 65000))
text = text:sub(65000 + 1)
end
end
old_chat_send_player(name, text)
end