lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


于 2012-6-8 5:43, Erik Cassel 写道:

Well, this is interesting. If I store the thread reference in a different thread's registry then there are no assertions:

int main(int argc, char* argv[])
{
int threadId;

lua_State* globalState = luaL_newstate();
lua_State* L = lua_newthread(globalState);

lua_sethook(L, hook, LUA_MASKLINE, 0);

luaL_loadstring(L, 
"i = 2\n" 
"print(i)");

lua_pushthread(L);
lua_xmove(L, globalState, 1);
threadId = luaL_ref(globalState, LUA_REGISTRYINDEX);

lua_resume(L, 0, 0);

luaL_unref(globalState, LUA_REGISTRYINDEX, threadId);   // **** THIS LINE CRASHES ****
}


-Erik





On Thu, Jun 7, 2012 at 9:07 AM, Erik Cassel <erik@roblox.com> wrote:
This is a follow-up to a recent thread about yielding in hooks. Thank
you all for help in clarifying how the line hook works.

Lua flags a stack overflow assertion in the following simple code
(both in 5.1 and 5.2). It is a small extension to the previous
example, but this one keeps a reference to thread L in the registry:


void hook(lua_State* L, lua_Debug* ar)
{
  lua_yield(L, 0);
}

int main(int argc, char* argv[])
{
  int threadId;

  lua_State* L = luaL_newstate();
  lua_sethook(L, hook, LUA_MASKLINE, 0);

  luaL_loadstring(L,
     "i = 2\n"
     "print(i)");

  lua_pushthread(L);
  threadId = luaL_ref(L, LUA_REGISTRYINDEX);

  lua_resume(L, 0, 0);

  luaL_unref(L, LUA_REGISTRYINDEX, threadId);   // **** THIS LINE CRASHES ****
}


The code registers a reference to L in the registry. It then steps one
line of Lua code ("i = 2") and the hook function yields. When it tries
to unreference L, the following assertion is fired:

      L->top < L->ci->top

This assertion seems to indicate a stack overflow.

Here is the stack:

       msvcr100d.dll!_wassert()  Line 153      C
       lua.exe!lua_rawgeti(lua_State * L=0x007b1d58, int idx=-1001000, int
n=0)  Line 648 + 0x45 bytes     C
       lua.exe!luaL_unref(lua_State * L=0x007b1d58, int t=-1001000, int
ref=3)  Line 545 + 0xf bytes    C


Is L in some invalid state after yielding in the hook? Is the stack
not usable? Is the registry corrupt?

-Erik

I guess the assertion erorr is not due to the luaL_ref/luaL_unref or the registry.
the real cause is you incorrect called the lua_resume in your first example

you should be aware that when a lua_State is created, it is in fact the main thread
associated with a newly created global state.
and the key point here is that the the C code manipulating the main thread is logically
impersonating the main thread as a CFunction at the base level.

in your first example, you resume the main thread by the main thread itself,
with the same stack frame/level. Although I didn't do much analysis,
but I suppose this were the cause of the assertion error.


BTW, your code looks strange, since lua_resume takes 2 argument, while your example gives 3.

oh, one more thing to clarify: there is no such thing as "a different thread's registry", since the registry
is a global value, associated with the global state, and shared by all threads of the same global state.