[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: LuaRC userdata stack corruption
- From: "Powers, Drew" <dpowers@...>
- Date: Sun, 19 Sep 2004 04:28:50 -0700
I apologize if this is the wrong place to post this and I hope the
is more readable than my last post :/
I have found another issue with the latest version of LuaRC
(from Subversion as of 9/15/04). Essentially, the collection of
with __gc metatables can corrupt existing stack elements.
If you have a userdata with __gc metatable at the stack top (L->top)
RC of 1, then push anything on the stack LuaRC asserts. The following
in the process of replacing the userdata with a string from
* userdata info is copied into a temp variable via lua_makeobjectbackup
* string object is created and placed at stack top (L->top) and its RC
* userdata RC (through temp var) is decremented because string is in
process of replacing it.
* lua_releaseobject (a LuaRC call) is called on userdata (through temp
because RC = 0.
* lua_releaseobject calls do1gcTM which checks if the userdata contains
metatable (which it does).
* the metatable is placed at the stack top (replacing the string we
put there <--- BAD) and userdata goes at top+1.
* the stack top is adjusted by +2 and the metatable __gc is called
the arg and function off and setting stack top back -2.
* the type of the object at stack top is LUA_TNIL (due to cleanup), but
gc still points to the __gc function object.
* we resume with the rest of the string move and assert because the gc
is not LUA_TSTRING.
My quick and dirty hack increments L->top before calling do1gcTM in
lua_releaseobject, then decrementing it afterwards which seems to
the corruption but it'll break the first time something puts two or more
Here's a repro:
int my_gc( lua_State* L )
lua_State* L = lua_open();
// create a userdata
void* buf = lua_newuserdata(L, 4);
*(unsigned int*)buf = 0x12345678;
// create a table to become the metatable
// add a gc function
lua_pushcclosure(L, my_gc, 0);
// add the table as a metatable
// put a copy of the userdata at L->top
// pop the original userdata off L->top-1 to get the RC of the one
// at L->top down to 1 (priming the condition my app is
// push something on stack to get the userdata back to L->top
// now push anything on the stack and it will assert.
lua_pushstring( L, "test" );