After trying and witnessing the incredible ease with which I could integrate Lua and LuaJIT into my game engine, I'm convinced that that's the scripting language I want to use. I would like to use it for my AI, unit descriptions, map triggers, et cetera. (as much as possible really). This question is not just applicable to gamedev, I can imagine creating a scriptable editor or window manager which can load external scripts (case in point: sublime text with python and package control)
But now I have a conundrum: I really appreciate the ease of use that the LuaJIT FFI offers to bind to my engine, but I don't want to provide free reign of the FFI to map authors for example. The incredible speed of lua-to-c calls via the FFI (when JITted) is also something I really want.
So ideally, I would write my own wrapper Lua files that bind to my engine with the FFI and export a nice module for map authors and modders to use. My alternative to this is to write a vanilla lua module, which is possible but much more cumbersome and slower.
I can't disable the FFI when compiling luajit because obviously I want to use it myself, but I don't see how to restrict the FFI on a per-script or per-module basis. Obviously the FFI needs to be active in the lua_State where I load my modules (after which I cant start loading the user-modified scripts). So what do I do? Is it even possible?
EDIT: In my mind, the ideal workflow would be:
NOTE: I'm aware that this would still not be a perfect (or even good sandbox), as Mike Pall already pointed out in some of his mails, but I still don't want to give map authors access to the FFI.
Maybe I do not understand the issue, but if you use a normal Lua sandbox in which the FFI is not accessible, what is the problem?
For instance:
ffi = require "ffi"
ffi.cdef([[int printf(const char *fmt, ...);]])
function say_hello()
ffi.C.printf("%s", "hello, ");
end
my_user_script = [[
say_hello()
ffi.C.printf("%s\n", "world")
]]
f = loadstring(my_user_script)
print("=== without sandbox ===")
print(pcall(f))
print("=== with sandbox ===")
setfenv(f,{say_hello = say_hello})
print(pcall(f))
This should output:
=== without sandbox ===
hello, world
true
=== with sandbox ===
hello, false [string "say_hello()..."]:2: attempt to index global 'ffi' (a nil value)
Note that you also need to be careful not to leak FFI cdata into the sandbox. There is a paragraph about this in the LuaJIT documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With