lua-users home
lua-l archive

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


Curiously enough, I am calling coroutine.create via a lua_call or lua_pcall and either end up with memory corruption that prevents further scripts execution with message "error in error handling" or a simple crash in GC. lua_[p]call itself executes with no problems taking 1 parameter and returning a new coroutine/lua_State* on the stack. But after this things go berserk. 

In my test run pState == pMainState (see code below). Call to lua_pcall succeeds leaving a new lua_State* on the stack. Using lua_call instead of lua_pcall makes no difference. I don't override Lua's memory allocation facilities. Commenting out lua_pcall fixes the problem. I did add one more member variable (void* mpMyData) to lua_State structure that I placed before CommonHeader. So, this variable can technically be a problem, I suspect.

Here is the simplified code that I tested 

///////////////////////////////////////////////////////////////////////
// Takes a LUA function as parameter 1
//
Sint32 nsGZLua5ThreadLib::Create(lua_State* pState)
{
   lua_State* pMainState = G(pState)->mainthread;

   Sint32 main_tos = lua_gettop(pMainState);
   lua_xmove(pState, pMainState, 1);  // move the function to pMainState stack
   Sint32 lf_si = lua_gettop(pMainState);

   // call old create
   lua_pushnumber(pMainState, kThreadsOldCreateKey);
   lua_rawget(pMainState, cIGZLua5Thread::kSIREGISTRY); // puts the precached coroutine.create on top
   lua_pushvalue(pMainState, lf_si); // push the lua function on top
   lua_pcall(pMainState, 1, 1);  // call coroutine.create
   
   lua_settop(pMainState, main_tos);  // restore the stack for the main thread
   return 0;
}

AB

-----Original Message-----
From: Benoit Germain [mailto:bgermain@ubisoft.fr]
Sent: Thursday, January 30, 2003 7:55 AM
To: Multiple recipients of list
Subject: is this a bug in lua core 5.0b ?

Hi,

I have replaced the system memory allocator with Doug Lea's malloc, version
2.7.2, found here: http://gee.cs.oswego.edu/pub/misc/malloc.c, and I get a
crash because of memory corruption.
Here is what I am doing at the time of the crash:

I pcall from C a function created by coroutine.wrap(). This function resumes
the coroutine, but an error is raised by luaG_ordererror(), which causes the
program to enter luaG_errormsg a first time:

luaG_errormsg(lua_State * L=0x011c1c50)  Ligne 568
luaG_runerror(lua_State * L=0x011c1c50, const char * fmt=0x00b3af48, ...)
Ligne 577 + 0x9
luaG_ordererror(lua_State * L=0x011c1c50, const lua_TObject * p1=0x011c7f60,
const lua_TObject * p2=0x011c7f58)  Ligne 543 + 0x16
luaV_lessthan(lua_State * L=0x011c1c50, const lua_TObject * l=0x011c7f60,
const lua_TObject * r=0x011c7f58)  Ligne 233 + 0x11
luaV_execute(lua_State * L=0x011c1c50)  Ligne 578 + 0xa9
resume(lua_State * L=0x011c1c50, void * ud=0x0012f3ec)  Ligne 352 + 0x9
luaD_rawrunprotected(lua_State * L=0x011c1c50, void (lua_State *, void *)*
f=0x006aa4d0, void * ud=0x0012f3ec)  Ligne 96 + 0xd
lua_resume(lua_State * L=0x011c1c50, int nargs=3)  Ligne 368 + 0x12
auxresume(lua_State * L=0x011b03d0, lua_State * co=0x011c1c50, int narg=3)
Ligne 548 + 0xd
luaB_auxwrap(lua_State * L=0x011b03d0)  Ligne 583 + 0x1a
luaD_precall(lua_State * L=0x011b03d0, lua_TObject * func=0x011c86e0)  Ligne
273 + 0x12
luaD_call(lua_State * L=0x011b03d0, lua_TObject * func=0x011c86e0, int
nResults=0)  Ligne 318 + 0xd
f_call(lua_State * L=0x011b03d0, void * ud=0x0012fc20)  Ligne 666 + 0x16
luaD_rawrunprotected(lua_State * L=0x011b03d0, void (lua_State *, void *)*
f=0x0069d100, void * ud=0x0012fc20)  Ligne 96 + 0xd
luaD_pcall(lua_State * L=0x011b03d0, void (lua_State *, void *)*
func=0x0069d100, void * u=0x0012fc20, int old_top=16, int ef=8)  Ligne 421 +
0x11
lua_pcall(lua_State * L=0x011b03d0, int nargs=3, int nresults=0, int
errfunc=-5)  Ligne 679 + 0x20

since there is no error handler, LUA_ERRRUN is simply thrown, which returns
control to lua_resume(). Then luaB_auxwrap() propagates the error, which
causes the program to enter luaG_errormsg a second time.
The contents of L at that point are as follows:

-       L       0x011b03d0      lua_State *
+       next    0xcdcdcdcd      GCObject *
        tt      8 '?'   unsigned char
        marked  205 'Í' unsigned char
+       top     0x011c8c78      lua_TObject *
+       base    0x011c86e8      lua_TObject *
+       l_G     0x011b0430      global_State *
+       ci      0x011b064c      CallInfo *
+       stack_last      0x011c8c40      lua_TObject *
+       stack   0x011c86d0      lua_TObject *
        stacksize       180     int
+       end_ci  0x011b06d8      CallInfo *
+       base_ci 0x011b0638      CallInfo *
        size_ci 8       unsigned short
        nCcalls 1       unsigned short
        hookmask        7 '?'   unsigned char
        allowhook       1 '?'   unsigned char
        hookinit        1 '?'   unsigned char
        basehookcount   0       int
        hookcount       -4217   int
        hook    0x00667bd7 lua::lua_interface::LuaDebugger::theHook(struct
lua_State *,struct lua_Debug *) void (lua_State *, lua_Debug *)*
+       _gt     {...}   lua_TObject
+       openupval       0x00000000      GCObject *
+       gclist  0xcdcdcdcd      GCObject *
+       errorJmp        0x0012f9a0      lua_longjmp *
        errfunc 8       int


As you can see, we have:
L->stacksize == 180
and
        L->top-L->stack 181     unsigned long

that is to say, the stack is full. Unfortunately, we can see that
luaG_errormsg pushes two objects on the stack, and resizes it only
afterward:

void luaG_errormsg (lua_State *L) {
  if (L->errfunc != 0) {  /* is there an error handling function? */
    StkId errfunc = restorestack(L, L->errfunc);
    if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
    setobjs2s(L->top, L->top - 1);  /* move argument */
    setobjs2s(L->top - 1, errfunc);  /* push function */ <-- here is the
problem
    incr_top(L);
    luaD_call(L, L->top - 2, 1);  /* call it */
  }
  luaD_throw(L, LUA_ERRRUN);
}


As a result, when the error function is pushed on the stack, it goes beyond
the limit of the current memory block where the stack resides, thus causing
the header of the adjacent block in RAM to be corrupted.


What do you think of this ?


Regards,

Benoit.