Fix C stack overflow on Nether portal destruction

Before this patch, destroying an obsidian Nether portal frame destroyed
Nether portal nodes recursively. In Minetest binaries compiled with Lua
5.1 (i.e. without LuaJIT) this would cause a stack overflow when a huge
portal (23×23) was destroyed, crashing the server.

This patch implements Nether portal destruction using node timers. When
a portal node's timer triggers, it starts the timers of adjacent portal
nodes with the same orientation and no active timer and deletes itself.

Attempts to solve this problem using minetest.after() seemed promising,
but rubenwardy pointed out that anything relying on minetest.after() is
bound to fail if a server shuts down while portal nodes are destroyed.
This commit is contained in:
Nils Dagsson Moskopp 2022-02-15 21:21:45 +01:00
parent de9f2479eb
commit 4b91ae9522
No known key found for this signature in database
GPG Key ID: A3BC671C35191080
1 changed files with 9 additions and 2 deletions

View File

@ -76,8 +76,11 @@ local function destroy_nether_portal(pos)
local check_remove = function(pos, orientation)
local node = minetest.get_node(pos)
if node and (node.name == "mcl_portals:portal" and (orientation == nil or (node.param2 == orientation))) then
minetest.log("action", "[mcl_portal] Destroying Nether portal at " .. minetest.pos_to_string(pos))
return minetest.remove_node(pos)
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
minetest.log("action", "[mcl_portal] Queuing Nether portal for destruction at " .. minetest.pos_to_string(pos))
timer:start(0.05)
end
end
end
if obsidian then -- check each of 6 sides of it and destroy every portal:
@ -154,6 +157,10 @@ minetest.register_node("mcl_portals:portal", {
},
groups = {portal=1, not_in_creative_inventory = 1},
on_destruct = destroy_nether_portal,
on_timer = function(pos, elapsed)
minetest.remove_node(pos)
return false
end,
_mcl_hardness = -1,
_mcl_blast_resistance = 0,