2018-06-24 22:33:00 +02:00
|
|
|
--[[
|
|
|
|
|
|
|
|
SaferLua [safer_lua]
|
|
|
|
====================
|
|
|
|
|
|
|
|
Copyright (C) 2018 Joachim Stolberg
|
|
|
|
|
|
|
|
LGPLv2.1+
|
|
|
|
See LICENSE.txt for more information
|
|
|
|
|
|
|
|
environ.lua:
|
|
|
|
|
|
|
|
]]--
|
|
|
|
|
2018-06-26 23:04:25 +02:00
|
|
|
safer_lua.MaxCodeSize = 2000 -- size in length of byte code
|
2018-06-30 00:23:18 +02:00
|
|
|
safer_lua.MaxTableSize = 1000 -- sum over all table sizes
|
2018-06-24 15:01:33 +02:00
|
|
|
|
|
|
|
|
2018-06-30 00:23:18 +02:00
|
|
|
local function memsize()
|
|
|
|
return safer_lua.MaxTableSize
|
|
|
|
end
|
|
|
|
|
2018-06-24 15:01:33 +02:00
|
|
|
local BASE_ENV = {
|
2018-06-30 00:23:18 +02:00
|
|
|
Array = safer_lua.Array,
|
2018-06-24 15:01:33 +02:00
|
|
|
Store = safer_lua.Store,
|
2018-06-30 00:23:18 +02:00
|
|
|
Set = safer_lua.Set,
|
|
|
|
memsize = memsize,
|
2018-06-24 15:01:33 +02:00
|
|
|
math = {
|
2018-06-25 20:42:47 +02:00
|
|
|
floor = math.floor,
|
|
|
|
abs = math.abs,
|
|
|
|
max = math.max,
|
|
|
|
min = math.min,
|
|
|
|
random = math.random,
|
2018-06-24 15:01:33 +02:00
|
|
|
},
|
2018-06-25 20:42:47 +02:00
|
|
|
tonumber = tonumber,
|
|
|
|
tostring = tostring,
|
|
|
|
type = type,
|
2018-06-24 15:01:33 +02:00
|
|
|
ticks = 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
local function map(dest, source)
|
|
|
|
for k,v in pairs(source) do
|
|
|
|
dest[k] = v
|
|
|
|
end
|
|
|
|
return dest
|
|
|
|
end
|
|
|
|
|
2018-06-30 00:23:18 +02:00
|
|
|
local function calc_used_mem_size(env)
|
|
|
|
local size = 0
|
|
|
|
for key,val in pairs(env) do
|
|
|
|
if type(val) == "table" and val.size ~= nil then
|
|
|
|
size = size + val.size() or 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return size
|
|
|
|
end
|
|
|
|
|
2018-06-24 15:01:33 +02:00
|
|
|
function safer_lua.config(max_code_size, max_table_size)
|
|
|
|
safer_lua.MaxCodeSize = max_code_size
|
|
|
|
safer_lua.MaxTableSize = max_table_size
|
|
|
|
end
|
|
|
|
|
|
|
|
local function compile(pos, text, label, err_clbk)
|
|
|
|
if safer_lua:check(text, label, err_clbk) == 0 then
|
|
|
|
text = text:gsub("%$", "S:")
|
|
|
|
local code, err = loadstring(text)
|
|
|
|
if not code then
|
2018-06-30 00:23:18 +02:00
|
|
|
err = err:gsub("%(load%):", label)
|
2018-06-24 15:01:33 +02:00
|
|
|
err_clbk(pos, err)
|
|
|
|
else
|
|
|
|
return code
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function safer_lua.init(pos, init, loop, environ, err_clbk)
|
|
|
|
if #init > safer_lua.MaxCodeSize then
|
|
|
|
err_clbk(pos, "init() Code size limit exceeded")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if #loop > safer_lua.MaxCodeSize then
|
|
|
|
err_clbk(pos, "loop() Code size limit exceeded")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local code = compile(pos, init, "init() ", err_clbk)
|
|
|
|
if code then
|
|
|
|
local env = BASE_ENV
|
|
|
|
env.S = {}
|
|
|
|
env.S = map(env.S, environ)
|
|
|
|
setfenv(code, env)
|
|
|
|
local res, err = pcall(code)
|
|
|
|
if not res then
|
|
|
|
err = err:gsub("%[string .+%]:", "init() ")
|
|
|
|
err_clbk(pos, err)
|
|
|
|
else
|
|
|
|
env = getfenv(code)
|
|
|
|
code = compile(pos, loop, "loop() ", err_clbk)
|
|
|
|
if code then
|
|
|
|
setfenv(code, env)
|
|
|
|
return code
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function safer_lua.run_loop(pos, elapsed, code, err_clbk)
|
|
|
|
local env = getfenv(code)
|
|
|
|
env.elapsed = elapsed
|
2018-06-30 00:23:18 +02:00
|
|
|
if elapsed < 0 then -- event?
|
|
|
|
env.event = true
|
|
|
|
else
|
|
|
|
env.event = false
|
|
|
|
env.ticks = env.ticks + 1
|
|
|
|
end
|
2018-06-24 15:01:33 +02:00
|
|
|
local res, err = pcall(code)
|
2018-06-30 00:23:18 +02:00
|
|
|
if calc_used_mem_size(env) > safer_lua.MaxTableSize then
|
|
|
|
err_clbk("Memory limit exceeded")
|
2018-06-24 15:01:33 +02:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
if not res then
|
|
|
|
err = err:gsub("%[string .+%]:", "loop() ")
|
|
|
|
err_clbk(pos, err)
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|