Skip to content

Commit

Permalink
Unset metatable when destroying C++-objects.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Oberon00 committed Oct 18, 2012
1 parent 864b61c commit a83aae7
Showing 1 changed file with 3 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/object_rep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit a83aae7

Please sign in to comment.