[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: __gc userdata problem
- From: Dominik Zaczkowski <dmz@...>
- Date: Mon, 26 Aug 2013 16:02:28 +0200
Hello,
I have problem with userdata and garbage collection, until now I thought
that after userdata __gc
metamethod is called it means that lua cannot touch my data in any way,
so I can free my
resources. However, it is not the case, there is possibility that
table's __gc metamethod can touch
my userdata after it was collected.
Because my English is far from perfect I attach example to show what I
mean.
How can I be sure that my userdata is gone, and I can free its resources?
Only solution that I see is to mark userdata as free on __gc and then
check for that it in every
function exposed to lua. Is there a better way? Or is it possible to
disable __gc on tables?
My lua version is 5.2.2.
Regards
Dominik
#include <assert.h>
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
// "free" resources
static int ud_gc(lua_State *L)
{
int *ud = luaL_checkudata(L, 1, "ud");
*ud = 0;
puts("ud gc");
}
// print userdata resources
static int ud_print(lua_State *L)
{
int *ud = luaL_checkudata(L, 1, "ud");
assert(*ud > 0);
printf("%d\n", *ud);
}
int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L); // oddly, without this lua doesn't call
// table's __gc metamethods
// table with __gc method, which prints userdata
const char *code =
"tab = {} \
setmetatable(tab, {__gc = function (self) ud_print(self[1]) end })";
luaL_dostring(L, code);
// new userdata
int *ud = lua_newuserdata(L, sizeof (*ud));
*ud = 1;
// metatable for userdata
luaL_newmetatable(L, "ud");
lua_pushcfunction(L, ud_gc);
lua_setfield(L, -2, "__gc");
lua_setmetatable(L, -2);
// set new userdatad as global var
lua_setglobal(L, "ud");
// set test func as global var
lua_pushcfunction(L, ud_print);
lua_setglobal(L, "ud_print");
luaL_dostring(L, "tab[1] = ud");
luaL_dostring(L, "ud = nil");
luaL_dostring(L, "tab = nil");
// at this point ud is no longer reachable, so it's __gc method
// is called, but its still accessed in tab's __gc method
lua_gc(L, LUA_GCCOLLECT, 0); // assertion failed
return 0;
}