There's lua_sethook which can be used to tell the interpreter to call a hook after every 'count' instructions executed. This way you can monitor the user script and terminate it if it eats up its quota:
int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
This can also be used from Lua:
debug.sethook(function() print("That's enough for today"); os.exit(0); end, "", 10000)
for i=1,10000 do end
If you use the techniques from http://lua-users.org/wiki/SandBoxes then you can set up a safe execution environment with sethook()
and friends entirely from Lua and then switch to sandbox mode while executing the user script. I've tried that here, just for you to get started:
-- set an execution quota
local function set_quota(secs)
local st=os.clock()
function check()
if os.clock()-st > secs then
debug.sethook() -- disable hooks
error("quota exceeded")
end
end
debug.sethook(check,"",100000);
end
-- these are the global objects, the user can use:
local env = {print=print}
-- The user code is allowed to run for 5 seconds.
set_quota(5)
-- run code under environment:
local function run(untrusted_code)
local untrusted_function, message = loadstring(untrusted_code)
if not untrusted_function then return nil, message end
setfenv(untrusted_function, env)
return pcall(untrusted_function)
end
-- here is the user code:
local userscript=[[
function fib(n)
if n<2 then return n
else return fib(n-2)+fib(n-1)
end
end
for n=1,42 do print(n,fib(n)) end
]]
-- call it:
local r,m=run(userscript)
print(r,m)
This should print values of fib() for 5 seconds and then show an error.