覆盖require后调用`lua_getfield()`时崩溃

时间:2018-07-25 13:54:05

标签: c++ lua require

此问题与@Henri_Menke对此问题的回答有关:How to get preloaded module name in C++

我正在尝试使用自己的版本覆盖require函数,以便在Lua脚本中获得预加载的模块名称。

这是我的代码:

#include "lua.hpp"

void main()
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_settop(L, 0);
    luaL_dostring(L, "local require_original = require\n"
                     "function require(name, ...)\n"
                         "current_module = name\n"
                         "require_original(name, ...)\n"
                         "current_module = nil\n"
                     "end\n"); //if I comment out this chunk, it works fine
    luaL_dostring(L, "package.preload['test'] = function ()\n"
                         "local test = {}\n"
                         "print('While loading:', current_module)\n"
                         "function test.update() print('Updated!') end\n"
                         "return test\n"
                     "end\n");
    lua_getglobal(L, "require");
    lua_pushstring(L, "test");
    if (lua_pcall(L, 1, LUA_MULTRET, 0))
    {
        std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);
    }
    int top = lua_gettop(L);
    lua_getfield(L, -1, "update"); //crashes here
    if (lua_isfunction(L, -1))
    {
        lua_pushnil(L);
        if (lua_pcall(L, 1, LUA_MULTRET, 0))
        {
            std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
            lua_pop(L, 1);
        }
    }
    lua_close(L);
}

但是,它在调用lua_getfield(L, -1, "update");时崩溃。

当我注释掉Lua脚本的第一块(第一luaL_dostring)时,它不再崩溃。

如果我使用自己的require版本,我不明白为什么它会崩溃。

我该如何解决?

1 个答案:

答案 0 :(得分:1)

我忘记从覆盖的require函数返回模块表。抱歉。

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

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_settop(L, 0);
    luaL_dostring(L, "local require_original = require\n"
                     "function require(name, ...)\n"
                         "current_module = name\n"
                         "local val = table.pack(require_original(name, ...))\n"
                         "current_module = nil\n"
                         "return table.unpack(val,1,val.n)\n"
                     "end\n"); //if I comment out this chunk, it works fine
    luaL_dostring(L, "package.preload['test'] = function ()\n"
                         "local test = {}\n"
                         "print('While loading:', current_module)\n"
                         "function test.update() print('Updated!') end\n"
                         "return test\n"
                     "end\n");
    lua_getglobal(L, "require");
    lua_pushstring(L, "test");
    if (lua_pcall(L, 1, LUA_MULTRET, 0))
    {
        std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);
    }
    int top = lua_gettop(L);
    lua_getfield(L, -1, "update"); //crashes here
    if (lua_isfunction(L, -1))
    {
        lua_pushnil(L);
        if (lua_pcall(L, 1, LUA_MULTRET, 0))
        {
            std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
            lua_pop(L, 1);
        }
    }
    lua_close(L);
}
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 test.cpp -llua5.2
test.cpp:28:9: warning: unused variable 'top' [-Wunused-variable]
    int top = lua_gettop(L);
        ^
1 warning generated.
$ ./a.out 
While loading:  test
Updated!