for level = 1, math.hugedo local info = debug.getinfo(level, "Sl") ifnot info then break end
if info.what == "C"then print(string.format("%d\t C function", level)) else print(string.format("%d\t[%s]:%d", level, info.short_src, info.currentline)) end end end
localfunctionhook() local f = debug.getinfo(2, "f").func local count = Counters[f] if count == nilthen Counters[f] = 1 Names[f] = debug.getinfo(2, "Sn") else Counters[f] = count + 1 end end
functiongetname(func) local n = Names[func] if n.what == "C"then return n.name end
local lc = string.format("[%s]:%d", n.short_src, n.linedefined) if n.what ~= 'main'and n.namewhat ~= ""then returnstring.format("%s (%s)", lc, n.name) else return lc end end
functionshow() for func, count inpairs(Counters) do print(getname(func), count) end end
local f = assert(loadfile(arg[1])) debug.sethook(hook, "c") f() debug.sethook() show()
沙盒
利用函数 load 在受限的环境中运行 Lua 代码是非常简单的。但是我们仍然可能被消耗大量 CPU 时间或内存的脚本进行拒绝服攻击。反射以调试钩子的形式,提供了一种避免攻击的方式。
functionreceive(connection) connection:settimeout(0) local s, status, partial = connection:receive(2^10) ifstatus == "timeout"then coroutine.yield(connection) end return s or partial, status end
functiondownload(host, file) local c = assert(socket.connect(host, 80)) local count = 0 local request = string.format( "GET %s HTTP/1.0\r\nhost: %s\r\n\r\n", file, host ) c:send(request)
whiletruedo local s, status = receive(c) count = count + #s ifstatus == "closed"then break end end
c:close() print(file, count) end
tasks = {}
functionget(host, file) local co = coroutine.wrap(function() download(host, file) end)
table.insert(tasks, co) end
functiondispatch() local i = 1 local timeout = {}
whiletruedo if tasks[i] == nilthen if tasks[1] == nilthen break end i = 1 timedout = {} end
local res = task[i]() ifnot res then table.remove(tasks, i) else i = i + 1 timeout[#timeout + 1] = res if #timeout == #tasks then socket.select(timedout) end end end end