于 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.
|