当元表 __index 指向函数并且未使用返回值时 Lua 崩溃

Posted

技术标签:

【中文标题】当元表 __index 指向函数并且未使用返回值时 Lua 崩溃【英文标题】:Lua crashed when metatable __index pointing to a function and returned value is not used 【发布时间】:2021-09-11 14:28:45 【问题描述】:

我正在尝试将函数用作元表__index 以实现更大的灵活性,但是当返回的值未分配给 Lua 端的某个变量时它崩溃了。

这是C++部分,它只是创建了一个表变量,其__index指向一个C函数,该函数只是返回一个固定的数值:

int meta_index( lua_State* lua )

    juce::Logger::writeToLog( "meta_index with key " + juce::String( lua_tostring( lua, 2 ) ) );
    lua_pushnumber( lua, 123.456 );
    return 1;



int main()

    lua_State* lua = luaL_newstate();
    luaL_openlibs( lua );

    // create a table with __index slot
    lua_createtable( lua, 0, 0 );
    lua_pushstring( lua, "__index" );
    lua_pushcfunction( lua, meta_index );
    lua_settable( lua, -3 );
    lua_setglobal( lua, "test_meta" );

    // run lua code
    luaL_loadstring( lua, lua_src );
    lua_call( lua, 0, 0 );
    lua_close( lua );

这是导致崩溃的 Lua 代码:

const char* lua_src =
    "a = \n"
    "setmetatable(a, test_meta)\n"
    "a.foo\n";

代码崩溃之前 C 函数meta_index 实际被调用,并声称错误消息尝试调用字符串值

但是,如果我将触发元索引的表达式a.foo 放在赋值右侧,则代码完成时不会出现错误并产生预期的结果:

const char* lua_src =
    "a = \n"
    "setmetatable(a, test_meta)\n"
    "bar = a.foo\n"
    "print(bar)\n";

Lua 似乎将a.foobar = a.foo 中的foo 视为不同的东西,它的实际规则是什么?

【问题讨论】:

【参考方案1】:

下面的代码无法编译,因为像a.foo 这样的表达式在 Lua 中不是语句:

a = 
setmetatable(a, test_meta)
a.foo

错误信息是

4: syntax error near <eof>

此字符串在luaL_loadstring 之后留在堆栈顶部。因此,当您调用 lua_call 时会出现错误 attempt to call a string value

底线:始终检查luaL_loadstring 的返回码并打印任何错误消息。

【讨论】:

以上是关于当元表 __index 指向函数并且未使用返回值时 Lua 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

__newindex元方法

Lua——3.元表Metatable

Lua元表和元方法DaemonCoder

lua奇怪的继承

lua的元表与元方法

lua元表