2

I have different metatables in my project. But if I create a value A and assign the metatable "X" and creates a second value B and attach metatable "Y", A gets the Y metatable, too! Here is a simplified C function for demonstration:

#include <errno.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
// shoudl create t["obj"] = <userdata> with metatable = "Obj" but gets "OtherType"
int create_table_with_object(lua_State *L)
{
        lua_newtable(L);
        lua_pushlightuserdata(L, (void*)0x1234);
        luaL_setmetatable(L, "Obj"); // This Type is already registered with lua_newmetatable()
        lua_setfield(L, -2, "obj");

        luaL_newmetatable(L, "OtherType");
        lua_pushinteger(L, 70);
        lua_setfield(L, -2, "ICameFromOtherType");
        lua_pop(L, 1); // just a dummy table

        // If we create another userdata object, the first one
        // gets the same type as this one!
        // Obj -> changes to "OtherType"
        // ### CRITICAL SECTION STRT ###
        lua_pushlightuserdata(L, (void*)0x5555);
        luaL_setmetatable(L, "OtherType");
        lua_setglobal(L, "JustADummyObj"); // this removes the value from the stack!
        // ### CRITICAL SECTION END  ###

        return 1;
}

int main(void)
{
        lua_State *L = luaL_newstate();
        luaL_openlibs(L);

        luaL_loadfile(L, "bug.lua");

        lua_pushcfunction(L, create_table_with_object);
        lua_setglobal(L, "create_table_with_object");

        luaL_newmetatable(L, "Obj");
        lua_pop(L, 1);

        int error;
        if(error = lua_pcall(L, 0, 0, 0))
        {
                fprintf(stderr, "Fatal error: \n");
                fprintf(stderr, "%s\n", lua_tostring(L, -1));
                return 1;
        }

        lua_close(L);

        return 0;
}

Lua Code:

local a = create_table_with_object()
print(getmetatable(a.obj).__name)

The output is "OtherType" but it should be "Obj". It seems that the second call to lua_setmetatable() overrides the table from other values?!

cytrinox
  • 1,846
  • 5
  • 25
  • 46
  • Calling the setmetatable overwrites any previous metatable set. So your code does exactly what you described, you set it to `Obj` first, and then overwrite it with `OtherType` – codingbunny Apr 20 '15 at 14:46
  • NekoNova: luaL_setmetatable() should only affect the value on top of the stack! But in my example, it also modifies other values. – cytrinox Apr 20 '15 at 14:50

1 Answers1

3

Ok, solved! lightuserdata in Lua shares one metatable (instead of one metatable per value). So changing the table for a lightuserdata value changes all other lightuserdata values!

cytrinox
  • 1,846
  • 5
  • 25
  • 46