Zack Lee
Zack Lee

Reputation: 3054

How to close a chunk of Lua code

I wonder if it's possible to only close a chuck of Lua code loaded with luaL_dostring so all the variables inside the chunk can be freed accordingly.

Here's my simple example:

lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_dostring(L, "a = 2"); // Script A
//How close the script A here?
luaL_dostring(L, "print(a)"); // Script B
lua_close(L);

This code prints 2 when I run it but I wonder if it's possible to somehow close(or free) only the firstly loaded chunk from the memory so it prints nil.

Upvotes: 0

Views: 723

Answers (1)

Henri Menke
Henri Menke

Reputation: 10939

Roughly speaking you want to sandbox script A, i.e. run it with a different global environment than script B. This can easily be done by backing up the global table into the registry and replacing it with an empty table (optionally populate the empty table with whatever you need inside the sandbox). After script A is finished you simply retrieve the old global table from the registry and make it the current global table again.

Apart from that I recommend reducing the usage of globals to an absolute minimum. In fact, I never use any global variables when I write Lua code. Usually I record information in local tables and pass these around. This is probably a more functional style of writing Lua.

#include <iostream>
#include <lua.hpp>

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    // START SANDBOX

    // Push the global table into the registry
    lua_pushglobaltable(L);
    lua_setfield(L, LUA_REGISTRYINDEX, "globals");

    // Push a new empty table and make it the global table
    lua_newtable(L);
    lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);

    // Script A
    if (luaL_dostring(L, "a = 2") != 0) {
        std::cerr << "lua:" << lua_tostring(L, -1) << '\n';
        lua_pop(L, 1);
    }

    // Retrieve the global table from the registry and make it the global table
    lua_getfield(L, LUA_REGISTRYINDEX, "globals");
    lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);

    // Optional: Remove the global table from the registry
    lua_pushnil(L);
    lua_setfield(L, LUA_REGISTRYINDEX, "globals");

    // END SANDBOX

    // Script B
    if (luaL_dostring(L, "print(a)") != 0) {
        std::cerr << "lua:" << lua_tostring(L, -1) << '\n';
        lua_pop(L, 1);
    }
    lua_close(L);
}
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2/ test.cpp -llua5.2
$ ./a.out 
nil

Upvotes: 3

Related Questions