13

What is the best way to remove or omit a Lua standard library package? For example remove the os library functions in a particular environment. The project in question is building Lua from the source files so I can edit the source, although I would rather do it through the API if possible.

Nick Van Brunt
  • 15,244
  • 11
  • 66
  • 92
  • See also [How can I create a secure Lua sandbox?](https://stackoverflow.com/questions/1224708/how-can-i-create-a-secure-lua-sandbox) – user Mar 20 '15 at 10:32

3 Answers3

31

See the file luaconf.h in the source kit for easy access to most compile-time configuration such as the actual type used for lua_Number.

See the file linit.c in the source kit for the list of core libraries that are loaded by calling luaL_openlibs().

Common practice is to copy that file to your application's source, and modify it to suit your needs, calling that copy's luaL_openlibs() in place of the core version. If you are compiling Lua privately and not linking to one of the pre-built binaries of the library, then you can find a method to do the equivalent that suits your needs.

Of course, you also don't need to compile or link to the sources for any library (such as os, found in loslib.c) that you choose to leave out of luaL_openlibs().

The only library that you probably can't leave out completely is the base library that provides things like pairs(), ipairs(), pcall(), tostring(), and lots more that can be really inconvenient to do without. When porting to an environment where some of these are problematic, it is usually a good idea to look closely at its implementation in lbaselib.c and either trim features from it or reimplement them to suit your needs.

Edit:

Another approach to including a different list of libraries in the interpreter is to not call luaL_openlibs() at all. Although provided as a convenience, like all of the auxiliary library, luaL_openlibs() is not mandatory. Instead, explicitly open just the libraries you want.

Chapter 5 of the reference manual talks about this:

To have access to these libraries, the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, it can open them individually by calling luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), luaopen_io (for the I/O library), luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). These functions are declared in lualib.h and should not be called directly: you must call them like any other Lua C function, e.g., by using lua_call.

That last sentence is occasionally the source of trouble, since older versions of Lua did not have that restriction. Each of the individual module's luaopen_xxx() functions follows the same protocol used by the require function. It should be passed a single argument: a string containing the name by which the module is known. The exception is the base module, which is passed an empty string because it has no actual name.

Here's a function that creates a new Lua state and opens only the base and package libraries:

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

lua_State *CreateBasicLua() {
    lua_State *L;

    L = luaL_newstate();
    if (L) {
        lua_pushcfunction(L, luaopen_base);
        lua_pushstring(L, "");
        lua_call(L, 1, 0);
        lua_pushcfunction(L, luaopen_package);
        lua_pushstring(L, LUA_LOADLIBNAME);
        lua_call(L, 1, 0);
    }
    return L;
}

It returns the new lua_State on success, or NULL on failure.

RBerteig
  • 41,948
  • 7
  • 88
  • 128
  • This does appear to be the correct way. It is too bad we have to edit a c file in the Lua source (or a copy in your project) to configure the standard libs. – Nick Van Brunt Jun 11 '09 at 19:35
  • 1
    I added a code fragment demonstrating an alternative to editing linit.c to get the customization you want. – RBerteig Jun 11 '09 at 23:29
  • Nice addition I would up it again if I could. – Nick Van Brunt Jun 14 '09 at 15:09
  • Why are you using "lua_pushcfunction" at the same time as "luaopen_"? This is redundant as far as I'm concerned. You can just call "luaopen_(L);" and it'll work just fine. Then you don't need to do "lua_call(L, 1, 0);" each time you load one! – LaKraven Nov 23 '11 at 14:47
  • 1
    In short, because the manual says to do it this way. "These functions are declared in lualib.h and should not be called directly: you must call them like any other Lua C function, e.g., by using lua_call." (Lua Reference Manual, Chapter 5, pg 65). The luaopen_xxx() functions are promised that they are called like any other C function, with a clean stack that has room for the usual number of temporaries. Calling it directly does not let the core make those guarantees. – RBerteig Nov 23 '11 at 23:46
  • Is it possible for a Lua script to get access to an unloaded library? Maybe by using require? It doesn't sound possible, but this is not 100% clear to me. – Sqeaky Mar 11 '12 at 20:57
  • 1
    Using `require"foo"` only works if some DLL reachable via the patterns in `package.cpath` contains a function named `luaopen_foo()` that behaves as expected when called. The base libraries are not found by default in any such DLL, as they were compiled in to the Lua core. However, it may be possible to load them anyway using `package.loadlib()` if you know where to look. There are also 3rd-party modules such as alien and ffi that can provide for calling arbitrary functions in any DLL that might be able to do the trick. In short, be careful what you let a script call. – RBerteig Mar 12 '12 at 22:49
  • 2
    The triplets in this code sample (pushcfunction/pushstring/call) is basically a shortened version of luaL_requiref(), which should probably be used if you're on 5.2. See lauxlib.c in the lua source tree – Aktau Aug 19 '13 at 08:49
10

Let's say you only want to open the base and package libraries. In Lua 5.2, the most concise way is

luaL_requiref(L, "_G", luaopen_base, 1);
luaL_requiref(L, "package", luaopen_package, 1);
lua_pop(L, 2);

This is how the luaL_openlibs function in linit.c works, except that it loads everything.

Jonathan Zrake
  • 603
  • 6
  • 9
  • Good answer, the accepted answer is more lua 5.1 style, while yours is good for lua 5.2. Currently looking for a way to reconcile lua 5.2 and luajit. (to anyone interested, just compare linit.c from 5.1 and 5.2, it'll become really obvious) – Aktau Aug 08 '13 at 11:15
  • This is the approach that the official documentation for 5.3 suggests. http://www.lua.org/manual/5.3/manual.html#6 – ellipse-of-uncertainty May 07 '15 at 16:01
3

I think that post answers your question, but a little more info on the subject. Be aware you can also just 'nil' entire tables.

So in your example the "os" lib you can do a "os = nil" then poof!, the "os" lib/table is gone. Doing a "os.time()" after this example would return an error for a now nonexistent lib/table. Furthermore if you just wanted to nix the "time" method alone in "os" you could just do "os.time = nil".