Fixed pure userdata being left on the stack during synchronized calls, potentially leading to unpersistable states.

This commit is contained in:
Florian Nücke 2014-06-04 14:55:20 +02:00
parent cb69a4b386
commit cb5a83ebbe

View File

@ -261,12 +261,6 @@ wrappedUserdataMeta = {
} }
local wrappedUserdata = setmetatable({}, wrappedUserdataMeta) local wrappedUserdata = setmetatable({}, wrappedUserdataMeta)
local function processArguments(...)
local args = table.pack(...)
unwrapUserdata(args)
return table.unpack(args)
end
local function processResult(result) local function processResult(result)
wrapUserdata(result) -- needed for metamethods. wrapUserdata(result) -- needed for metamethods.
if not result[1] then -- error that should be re-thrown. if not result[1] then -- error that should be re-thrown.
@ -286,24 +280,33 @@ local function invoke(target, direct, ...)
end end
if not result then if not result then
local args = table.pack(...) -- for access in closure local args = table.pack(...) -- for access in closure
unwrapUserdata(args)
result = select(1, coroutine.yield(function() result = select(1, coroutine.yield(function()
return table.pack(target.invoke(table.unpack(args, 1, args.n))) unwrapUserdata(args)
local result = table.pack(target.invoke(table.unpack(args, 1, args.n)))
wrapUserdata(result)
return result
end)) end))
end end
return processResult(result) return processResult(result)
end end
local function udinvoke(f, data, ...)
local args = table.pack(...)
unwrapUserdata(args)
local result = table.pack(f(data, table.unpack(args)))
return processResult(result)
end
-- Metatable for additional functionality on userdata. -- Metatable for additional functionality on userdata.
local userdataWrapper = { local userdataWrapper = {
__index = function(self, ...) __index = function(self, ...)
return processResult(table.pack(userdata.apply(wrappedUserdata[self], processArguments(...)))) return udinvoke(userdata.apply, wrappedUserdata[self], ...)
end, end,
__newindex = function(self, ...) __newindex = function(self, ...)
return processResult(table.pack(userdata.unapply(wrappedUserdata[self], processArguments(...)))) return udinvoke(userdata.unapply, wrappedUserdata[self], ...)
end, end,
__call = function(self, ...) __call = function(self, ...)
return processResult(table.pack(userdata.call(wrappedUserdata[self], processArguments(...)))) return udinvoke(userdata.call, wrappedUserdata[self], ...)
end, end,
__gc = function(self) __gc = function(self)
local data = wrappedUserdata[self] local data = wrappedUserdata[self]
@ -316,7 +319,9 @@ local userdataWrapper = {
-- reflection when loading again (and then immediately wrap it again). -- reflection when loading again (and then immediately wrap it again).
-- Collect wrapped callback methods. -- Collect wrapped callback methods.
__persist = function(self) __persist = function(self)
print("start saving userdata " .. tostring(wrappedUserdata[self]))
local className, nbt = userdata.save(wrappedUserdata[self]) local className, nbt = userdata.save(wrappedUserdata[self])
print("done saving userdata")
-- The returned closure is what actually gets persisted, including the -- The returned closure is what actually gets persisted, including the
-- upvalues, that being the classname and a byte array representing the -- upvalues, that being the classname and a byte array representing the
-- nbt data of the userdata value. -- nbt data of the userdata value.
@ -618,9 +623,7 @@ local function main()
elseif coroutine.status(co) == "dead" then elseif coroutine.status(co) == "dead" then
error("computer stopped unexpectedly", 0) error("computer stopped unexpectedly", 0)
else else
unwrapUserdata(result[2])
args = table.pack(coroutine.yield(result[2])) -- system yielded value args = table.pack(coroutine.yield(result[2])) -- system yielded value
wrapUserdata(args)
end end
end end
end end