Fix __gc and use raw metatable when it's disabled

This fixes a small __gc abuse I found, and also uses the raw metatable in a safe way when __gc is disabled. Both were tested.
This commit is contained in:
Soni L 2016-01-31 14:46:52 -02:00
parent ac64edd1c7
commit 07f452125c

View File

@ -683,7 +683,7 @@ sandbox = {
end end
local result = getmetatable(t) local result = getmetatable(t)
-- check if we have a wrapped __gc using mt -- check if we have a wrapped __gc using mt
if type(result) == "table" and rawget(result, "__gc") == sgc then if type(result) == "table" and system.allowGC() and rawget(result, "__gc") == sgc then
result = rawget(result, "mt") result = rawget(result, "mt")
end end
return result return result
@ -713,26 +713,32 @@ sandbox = {
if type(mt) ~= "table" then if type(mt) ~= "table" then
return setmetatable(t, mt) return setmetatable(t, mt)
end end
if type(rawget(mt, "__gc")) == "function" then if rawget(mt, "__gc") ~= nil then -- If __gc is set to ANYTHING not `nil`, we're gonna have issues
-- For all user __gc functions we enforce a much tighter deadline.
-- This is because these functions may be called from the main
-- thread under certain circumstanced (such as when saving the world),
-- which can lead to noticeable lag if the __gc function behaves badly.
local sbmt = {} -- sandboxed metatable. only for __gc stuff, so it's
-- kinda ok to have a shallow copy instead... meh.
for k, v in next, mt do
sbmt[k] = v
end
sbmt.mt = mt
-- Garbage collector callbacks apparently can't be sandboxed after -- Garbage collector callbacks apparently can't be sandboxed after
-- all, because hooks are disabled while they're running. So we just -- all, because hooks are disabled while they're running. So we just
-- disable them altogether by default. -- disable them altogether by default.
if not system.allowGC() then if system.allowGC() then
sbmt.__gc = nil -- Silent fail for backwards compat. TODO error in OC 1.7 -- For all user __gc functions we enforce a much tighter deadline.
else -- This is because these functions may be called from the main
-- thread under certain circumstanced (such as when saving the world),
-- which can lead to noticeable lag if the __gc function behaves badly.
local sbmt = {} -- sandboxed metatable. only for __gc stuff, so it's
-- kinda ok to have a shallow copy instead... meh.
for k, v in next, mt do
sbmt[k] = v
end
sbmt.__gc = sgc sbmt.__gc = sgc
sbmt.mt = mt
mt = sbmt
else
-- Don't allow marking for finalization, but use the raw metatable.
local gc = rawget(mt, "__gc")
rawset(mt, "__gc", nil) -- remove __gc
local ret = table.pack(pcall(setmetatable, t, mt))
rawset(mt, "__gc", gc) -- restore __gc
if not ret[1] then error(ret[2], 0) end
return table.unpack(ret, 1, ret.n)
end end
mt = sbmt
end end
return setmetatable(t, mt) return setmetatable(t, mt)
end, end,