Guard against dummy objects in 5.3+

Some time in the 5.3 dev stream (docs updated at
217f3a42), object refs started being invalidated
immediately on calling obj:remove(), such that
obj:get_pos() starts to return nil instead of the object's
last known position.

This can cause some crashes in NodeCore, where we
assume that our object is still valid (or usable as if it
were still valid) even though we're looping through
handlers and any one of them may have remove()d the
object before other handlers get a chance to fire.

Instead, just watch for unexpected nil returns from
functions we expect would never return nil (e.g.
get_pos or get_properties) and return if we hit one.
We can assume all other calls will be non-nil after that
one, as long as we stay in the same function flow.
This commit is contained in:
Aaron Suen 2020-05-18 18:36:06 -04:00
parent 1d0f9aa81f
commit 9c9eb4b85a
8 changed files with 23 additions and 9 deletions

View File

@ -116,15 +116,21 @@ nodecore.register_item_entity_step(function(self, dtime)
local t = (self.aismtimer or 0) + dtime
while t >= 1 do
t = t - 1
local pos = self.object:get_pos()
if not pos then return end
local setstack
checkstack(ItemStack(self.itemstring), {
pos = self.object:get_pos(),
pos = pos,
obj = self.object,
ent = self,
set = function(s)
if s:is_empty() then return self.object:remove() end
self.itemstring = s:to_string()
end
set = function(s) setstack = s end
})
if setstack then
if setstack:is_empty() then
return self.object:remove()
end
self.itemstring = setstack:to_string()
end
end
self.aismtimer = t
end)

View File

@ -73,6 +73,7 @@ nodecore.register_limited_abm({
})
local function dynamic_light_add(pos, level, ttl)
if not pos then return end
local name = minetest.get_node(pos).name
if not canreplace[name] then return end
if level < 1 then return end

View File

@ -96,6 +96,7 @@ end
function nodecore.entity_settle_check(on_settle, isnode)
return function(self)
local pos = self.object:get_pos()
if not pos then return end
if pos.y < nodecore.map_limit_min then
pos.y = nodecore.map_limit_min
self.object:set_pos(pos)

View File

@ -8,6 +8,7 @@ local math_floor, math_random
local cache = {}
function nodecore.item_ent_merge(pos)
if not pos then return end
pos = vector.round(pos)
local hash = minetest.hash_node_position(pos)

View File

@ -21,6 +21,7 @@ end
function nodecore.ent_prop_set(obj, def)
local old = obj:get_properties()
if not old then return end
if type(def) == "function" then
def = def(old, obj)
end

View File

@ -20,16 +20,17 @@ minetest.register_entity(modname .. ":stackent", {
initial_properties = nodecore.stackentprops(),
is_stack = true,
itemcheck = function(self)
local pos = self.object:get_pos()
local obj = self.object
local pos = obj:get_pos()
if not pos then return end
local stack = nodecore.stack_get(pos)
if not stack or stack:is_empty() then return self.object:remove() end
if not stack or stack:is_empty() then return obj:remove() end
local rp = vector.round(pos)
local props, scale, yaw = nodecore.stackentprops(stack,
rp.x * 3 + rp.y * 5 + rp.z * 7)
rp.y = rp.y + scale - 31/64
local obj = self.object
nodecore.ent_prop_set(obj, props)
if obj:get_yaw() ~= yaw then
obj:set_yaw(yaw)

View File

@ -10,7 +10,9 @@ nodecore.register_falling_node_on_setnode(function(self, node, meta)
and meta and meta.inventory and meta.inventory.solo then
local stack = ItemStack(meta.inventory.solo[1] or "")
if not stack:is_empty() then
local ent = minetest.add_item(self.object:get_pos(), stack)
local pos = self.object:get_pos()
if not pos then return end
local ent = minetest.add_item(pos, stack)
if ent then ent:set_velocity(self.object:get_velocity()) end
self.object:remove()
return true

View File

@ -19,6 +19,7 @@ local function maketick(mult, getname, oldtick)
end
local pos = self.object:get_pos()
if not pos then return end
pos.y = pos.y - 1
local vel = self.object:get_velocity()
local v = vel and -vel.y or 0