From a83aae710ccb5d4fad2d625e3c87008d450949cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Thu, 18 Oct 2012 18:22:33 +0200 Subject: [PATCH] Unset metatable when destroying C++-objects. When using Lua 5.2's __gc or luabinds __finalize metamethods, it is possible to access userdata after its __gc metamethod has been called. Unsetting its metatable turns undefined behavior in an ordinary Lua error (LUA_ERRGCMM). Assuming CppClass is a C++-class exported by luabind, the following code triggers undefined behavior (needs Lua 5.2 for __gc support for tables): t = { } setmetatable(t, {__gc = function(t) t.cppClass:method() end}) t.cppClass = CppClass() Since "the finalizers for objects are called in the reverse order that they were marked for collection" [1], this will try to call the __index metamethod of t.cppClass after the object_rep for it (and itself) has been destroyed. The call to t.cppClass:method() results in undefined behavior (in the particular case where I noticed the bug (on VS11, Win 7 x64) it was a pure virtual function call to luabind::detail::instance_holder::get()). With this patch applied, Lua will instead issue a runtime error because of indexing an userdata without __index metamethod. See also [1]: http://www.lua.org/manual/5.2/manual.html#2.5.1 http://lua.2524044.n2.nabble.com/userdata-access-after-gc-td7643253.html --- src/object_rep.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/object_rep.cpp b/src/object_rep.cpp index a8d990e7..c0e9d8d0 100755 --- a/src/object_rep.cpp +++ b/src/object_rep.cpp @@ -91,6 +91,9 @@ namespace luabind { namespace detail instance->release_dependency_refs(L); instance->~object_rep(); + + lua_pushnil(L); + lua_setmetatable(L, 1); return 0; }