luaL_setmetatable() 从其他值覆盖元表
luaL_setmetatable() overrides metatables from other values
我的项目中有不同的元table。但是,如果我创建一个值 A 并分配 metatable "X" 并创建第二个值 B 并附加 metatable "Y",A 将获得 Y metatable, 也!这是一个用于演示的简化 C 函数:
#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代码:
local a = create_table_with_object()
print(getmetatable(a.obj).__name)
输出是 "OtherType" 但它应该是 "Obj"。似乎对 lua_setmetatable() 的第二次调用覆盖了其他值的 table?!
好的,解决了!
Lua 中的 lightuserdata 共享一个 metatable(而不是每个值一个 metatable)。因此,更改 lightuserdata 值的 table 会更改所有其他 lightuserdata 值!
我的项目中有不同的元table。但是,如果我创建一个值 A 并分配 metatable "X" 并创建第二个值 B 并附加 metatable "Y",A 将获得 Y metatable, 也!这是一个用于演示的简化 C 函数:
#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代码:
local a = create_table_with_object()
print(getmetatable(a.obj).__name)
输出是 "OtherType" 但它应该是 "Obj"。似乎对 lua_setmetatable() 的第二次调用覆盖了其他值的 table?!
好的,解决了! Lua 中的 lightuserdata 共享一个 metatable(而不是每个值一个 metatable)。因此,更改 lightuserdata 值的 table 会更改所有其他 lightuserdata 值!