From 1408e8b9522186746137e90c672595c546323176 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 20 Jun 2015 12:21:52 +0200 Subject: [PATCH] Unset object's metatable in __gc Run the following code: do local d local f = function() d.visible = true end if _VERSION >= "Lua 5.2" then setmetatable({}, { __gc = f }) else getmetatable(newproxy(true)).__gc = f end d = drawin({}) end collectgarbage("collect") Awesome will segfault. The reason for this is that after the above code ran, all variables in it are unreferenced and will be garbage-collected at the next sweep phase. Lua runs garbage collectors in the inverse order that their corresponding objects were "marked" which means for the above code that the drawin's garbage collector will run before function f runs. So the code will access the drawin after its destructor already ran. Obviously, awesome's C code does not expect nor correctly deal with this situation and was dereferencing a NULL pointer. To fix this, this commit "unsets" the metatable of a userdata object when it is being garbage collected. Since the type of a userdata is inferred via its metatable, the object will no longer be accepted by luaA_toudata(). For the above code this will result in an unhelpful error message saying that something tried to index a userdata, but userdata cannot be indexed. At least we no longer crash and the traceback of the error will hopefully point at some __gc metamethod which should be enough of a hint to figure out the problem. Thanks-to: http://blog.reverberate.org/2014/06/beware-of-lua-finalizers-in-c-modules.html Signed-off-by: Uli Schlachter --- common/luaclass.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/luaclass.c b/common/luaclass.c index e8a95fd6..012426b0 100644 --- a/common/luaclass.c +++ b/common/luaclass.c @@ -179,6 +179,11 @@ luaA_class_gc(lua_State *L) for(; class; class = class->parent) if(class->collector) class->collector(item); + /* Unset its metatable so that e.g. luaA_toudata() will no longer accept + * this object. This is needed since other __gc methods can still use this. + */ + lua_newtable(L); + lua_setmetatable(L, 1); return 0; }