覆盖require后调用lua_getfield()时崩溃 [英] Crashes when calling `lua_getfield()` after overriding the require

查看:338
本文介绍了覆盖require后调用lua_getfield()时崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题与@Henri_Menke对此问题的回答有关:如何在C ++中获取预加载的模块名称

This question is related to @Henri_Menke's answer from this question : How to get preloaded module name in C++

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

I'm trying to override the require function with my own version so I can get the preloaded module name inside Lua script.

这是我的代码:

#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");时崩溃.

However, it crashes when calling lua_getfield(L, -1, "update");.

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

And it no longer crashes when I comment out the first chunk of Lua script(first luaL_dostring).

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

I don't understand why it crashes if I use my own version of require.

我该如何解决?

推荐答案

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

I forgot to return the module table from overridden require function. Sorry about that.

#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!

这篇关于覆盖require后调用lua_getfield()时崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆