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

这个问题与@Henri_Menke在这个问题的回答有关: 如何在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"); //如果我注释掉这一段,它就能正常工作
    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"); //在这里崩溃
    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

我该如何解决这个问题?

点赞
用户1944004
用户1944004

我忘了从重写的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"); //如果我注释掉这个语句块,它就可以正常工作
    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"); //这里崩溃了
    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!
2018-07-25 22:07:04