Search code examples
c++lualua-api

Lua crashed when metatable __index pointing to a function and returned value is not used


I'm trying to use function as metatable __index to achieve more flexibiilty, but it crashed when the returned value is not assigned to some variable in Lua side.

This is the C++ part, it just creates a table variable whose __index is pointing to a C function, the function just returns a fixed number value:

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

And this is the Lua code that causes crash:

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

The code crashed before C function meta_index is actually called, and it claims a error message attempt to call a string value.

However, if I put the expression a.foo who triggers meta indexing on the right of assignment, the code finishes with no error and produces expected result:

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

It seems Lua treats the foo in a.foo and bar = a.foo as different things, what is the actual rule for it?


Solution

  • The code below does not compile because expressions like a.foo are not statements in Lua:

    a = {}
    setmetatable(a, test_meta)
    a.foo
    

    The error message is

    4: syntax error near <eof>
    

    This string is left on the top of the stack after luaL_loadstring. Hence the error attempt to call a string value when you call lua_call.

    Bottom line: always check the return code of luaL_loadstring and print any error messages.