首页 > 解决方案 > 如何关闭一大块 Lua 代码

问题描述

我想知道是否可以只关闭一段加载的 Lua 代码,luaL_dostring以便相应地释放块内的所有变量。

这是我的简单示例:

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);

这段代码2在我运行时打印,但我想知道是否有可能以某种方式仅关闭(或释放)内存中第一个加载的块,以便打印nil

标签: c++lua

解决方案


粗略地说,您希望对脚本 A 进行沙盒处理,即使用与脚本 B 不同的全局环境运行它。这可以通过将全局表备份到注册表中并用空表替换它来轻松完成(可以选择用任何内容填充空表您需要在沙箱内)。脚本 A 完成后,您只需从注册表中检索旧的全局表并再次使其成为当前全局表。

除此之外,我建议将全局变量的使用减少到绝对最低限度。事实上,我在编写 Lua 代码时从不使用任何全局变量。通常我在本地表中记录信息并传递这些信息。这可能是一种更实用的 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

推荐阅读