/usr/share/lua/5.1/supple/objects.lua is in lua-supple 1.0.8-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | -- lib/supple/request.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Contextual object storage and identification. Wrapping and unwrapping.
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--
local gc = collectgarbage
local capi = require 'supple.capi'
local track = require 'supple.track'
local my_objects_by_obj = {}
local my_objects_by_tag = {}
local my_objects_expn_by_tag = {}
local my_name = "UNSET"
local my_counter = 0
local their_objects_by_tag = setmetatable({}, { __mode="v" })
local their_objects_by_obj = setmetatable({}, { __mode="k" })
local their_objects_refcnt = {}
local proc_call = nil
local type = capi.rawtype
local function clean_down(call_other_end)
track.enter("clean_down")
-- And force a full GC
gc "collect"
gc "collect"
gc "collect"
-- Call the other end if needed
if call_other_end then
proc_call("supple:clean_down", "__call")
end
-- And forget all our local objects
my_objects_by_obj = {}
my_objects_by_tag = {}
my_objects_expn_by_tag = {}
track.leave("clean_down")
end
local function set_name(newname)
my_name = newname
end
local function get_name()
return my_name
end
local function set_proc_call(pc)
proc_call = pc
end
local integral = {
["nil"] = true,
boolean = true,
string = true,
number = true,
}
local function new_tag(special_tag)
local retstr = special_tag
if not retstr then
if not my_name:match("%%d") then
retstr = ("%s:%d"):format(my_name, my_counter)
else
retstr = my_name:format(my_counter)
end
my_counter = my_counter + 1
end
return retstr
end
local function give(obj, special_tag)
-- If the object is integral, return it directly
if integral[type(obj)] then
return obj
end
-- If the passed object is one of their objects then "unwrap" it by
-- returning their tag.
track.enter("give", tostring(obj), tostring(special_tag))
local tag = their_objects_by_obj[obj];
if tag then
track.leave("give", "theirs", tag)
return { tag = tag }
end
-- If it's one of our objects which has already been wrapped, return our
-- tag
local tag = my_objects_by_obj[obj]
if tag then
track.leave("give", "ours", tag)
return my_objects_expn_by_tag[tag]
end
-- otherwise wrap it freshly for us and return that.
local tag = new_tag(special_tag)
local expn = capi.explain(obj, tag)
my_objects_by_obj[obj] = tag
my_objects_by_tag[tag] = obj
my_objects_expn_by_tag[tag] = expn
track.leave("give", "ours, new", tag)
return expn
end
local function receive(obj)
-- If the object is integral, return it directly
if integral[type(obj)] then
return obj
end
-- It's not integral, so it must be a tagged object
assert(type(obj) == "table")
assert(type(obj.tag) == "string")
local tag = obj.tag
track.enter("receive", tag)
-- First up, is it one of our objects?
local ret = my_objects_by_tag[tag]
if ret then
track.leave("receive", "ours", tostring(ret))
return ret
end
-- Now is it a known one of their objects?
ret = their_objects_by_tag[tag]
if ret then
track.leave("receive", "theirs", tostring(ret))
return ret
end
-- Okay, prepare a proxy?
assert(type(obj.type) == "string", "Type string expected, got " .. type(obj.type) .. " preparing proxy for " .. obj.tag)
local proxy, mt = capi.new_proxy(obj.type)
assert(capi.type(proxy) == obj.type)
their_objects_by_tag[tag] = proxy
their_objects_by_obj[proxy] = tag
their_objects_refcnt[tag] = (their_objects_refcnt[tag] or 0) + 1
-- Fill out the metatable
obj.methods = obj.methods or {}
if obj.type == "function" then
obj.methods[#obj.methods+1] = "__call"
end
if obj.type == "table" then
obj.methods[#obj.methods+1] = "__len"
obj.methods[#obj.methods+1] = "__index"
obj.methods[#obj.methods+1] = "__newindex"
obj.methods[#obj.methods+1] = "__next"
end
for _, name in ipairs(obj.methods or {}) do
local function meta_func(mobj, ...)
track.enter("meta_func", their_objects_by_obj[mobj], tag, name)
local ret = {proc_call(tag, name, ...)}
track.leave("meta_func", their_objects_by_obj[mobj], tag, name)
return unpack(ret)
end
mt[name] = meta_func
end
function mt:__gc()
their_objects_refcnt[tag] = their_objects_refcnt[tag] - 1
if their_objects_refcnt[tag] == 0 then
their_objects_refcnt[tag] = nil
proc_call(tag, "__gc")
end
end
-- And return the proxy object
track.leave("receive", "theirs, new", tostring(proxy))
return proxy
end
local function forget_mine(tag)
track.enter("forget_mine", tag)
local obj = my_objects_by_tag[tag]
assert(obj, "Trying to forget nil object: " .. tag)
my_objects_by_tag[tag] = nil
my_objects_by_obj[obj] = nil
my_objects_expn_by_tag[tag] = nil
track.leave("forget_mine", tag)
end
local function find_tag(obj)
if my_objects_by_obj[obj] then
return "my", my_objects_by_obj[obj]
end
if their_objects_by_obj[obj] then
return "their", their_objects_by_obj[obj]
end
end
local function get_object_anchor()
local ret = {}
for obj in pairs(their_objects_by_obj) do
ret[obj] = true
end
for obj in pairs(my_objects_by_obj) do
ret[obj] = true
end
return ret
end
return {
set_name = set_name,
get_name = get_name,
set_proc_call = set_proc_call,
give = give,
receive = receive,
clean_down = clean_down,
forget_mine = forget_mine,
find_tag = find_tag,
get_object_anchor = get_object_anchor,
}
|