2
0
Эх сурвалжийг харах

bug: GC metamethod calls could mess C/Lua stack syncronization

Roberto Ierusalimschy 22 жил өмнө
parent
commit
69dd9461e5
5 өөрчлөгдсөн 44 нэмэгдсэн , 19 устгасан
  1. 5 0
      bugs
  2. 11 7
      ldo.c
  3. 3 3
      lgc.h
  4. 8 3
      lstate.c
  5. 17 6
      lvm.c

+ 5 - 0
bugs

@@ -324,3 +324,8 @@ Thu Jan 23 11:29:06 UTC 2003
 >> protected
 (by Benoit Germain; since 5.0a)
 
+** ldo.c (and others)
+Fri Feb 28 14:20:33 EST 2003
+>> GC metamethod calls could mess C/Lua stack syncronization
+(by Roberto; since 5.0b)
+

+ 11 - 7
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 1.214 2003/02/27 11:52:30 roberto Exp roberto $
+** $Id: ldo.c,v 1.215 2003/02/28 15:42:08 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -292,7 +292,6 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
   while (wanted-- > 0)
     setnilvalue(res++);
   L->top = res;
-  luaC_checkGC(L);
 }
 
 
@@ -304,9 +303,10 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
 */ 
 void luaD_call (lua_State *L, StkId func, int nResults) {
   StkId firstResult;
+  lua_assert(!(L->ci->state & CI_CALLING));
   if (++L->nCcalls >= LUA_MAXCCALLS) {
     if (L->nCcalls == LUA_MAXCCALLS)
-      luaG_runerror(L, "stack overflow");
+      luaG_runerror(L, "C stack overflow");
     else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3)))
       luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
   }
@@ -315,6 +315,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
     firstResult = luaV_execute(L);  /* call it */
   luaD_poscall(L, nResults, firstResult);
   L->nCcalls--;
+  luaC_checkGC(L);
 }
 
 
@@ -428,10 +429,13 @@ struct SParser {  /* data to `f_parser' */
 };
 
 static void f_parser (lua_State *L, void *ud) {
-  struct SParser *p = cast(struct SParser *, ud);
-  Proto *tf = p->bin ? luaU_undump(L, p->z, &p->buff) :
-                       luaY_parser(L, p->z, &p->buff);
-  Closure *cl = luaF_newLclosure(L, 0, gt(L));
+  struct SParser *p;
+  Proto *tf;
+  Closure *cl;
+  luaC_checkGC(L);
+  p = cast(struct SParser *, ud);
+  tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff);
+  cl = luaF_newLclosure(L, 0, gt(L));
   cl->l.p = tf;
   setclvalue(L->top, cl);
   incr_top(L);

+ 3 - 3
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 1.17 2002/11/25 12:38:47 roberto Exp roberto $
+** $Id: lgc.h,v 1.18 2003/02/10 17:32:50 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -11,8 +11,8 @@
 #include "lobject.h"
 
 
-#define luaC_checkGC(L) if (G(L)->nblocks >= G(L)->GCthreshold) \
-			  luaC_collectgarbage(L)
+#define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \
+	if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); }
 
 
 void luaC_separateudata (lua_State *L);

+ 8 - 3
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 1.119 2003/02/10 17:32:50 roberto Exp roberto $
+** $Id: lstate.c,v 1.120 2003/02/13 16:07:57 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -206,9 +206,14 @@ static void callallgcTM (lua_State *L, void *ud) {
 LUA_API void lua_close (lua_State *L) {
   lua_lock(L);
   L = G(L)->mainthread;  /* only the main thread can be closed */
+  luaF_close(L, L->stack);  /* close all upvalues for this thread */
   luaC_separateudata(L);  /* separate udata that have GC metamethods */
-  /* repeat until no more errors */
-  while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0) /* skip */;
+  L->errfunc = 0;  /* no error function during GC metamethods */
+  do {  /* repeat until no more errors */
+    L->ci = L->base_ci;
+    L->base = L->top = L->ci->base;
+    L->nCcalls = 0;
+  } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0);
   lua_assert(G(L)->tmudata == NULL);
   close_state(L);
 }

+ 17 - 6
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 1.277 2003/02/27 11:52:30 roberto Exp roberto $
+** $Id: lvm.c,v 1.278 2003/02/27 12:33:07 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -393,15 +393,21 @@ static void Arith (lua_State *L, StkId ra,
 #define dojump(pc, i)	((pc) += (i))
 
 
+unsigned int count = 0;
+
 StkId luaV_execute (lua_State *L) {
   LClosure *cl;
   TObject *k;
   const Instruction *pc;
+unsigned int ii, ic, ir, io;
+ii = count;
  callentry:  /* entry point when calling new functions */
+ic = count;
   L->ci->u.l.pc = &pc;
   if (L->hookmask & LUA_MASKCALL)
     luaD_callhook(L, LUA_HOOKCALL, -1);
  retentry:  /* entry point when returning to old functions */
+ir = count;
   lua_assert(L->ci->state == CI_SAVEDPC ||
              L->ci->state == (CI_SAVEDPC | CI_CALLING));
   L->ci->state = CI_HASFRAME;  /* activate frame */
@@ -412,6 +418,7 @@ StkId luaV_execute (lua_State *L) {
   for (;;) {
     const Instruction i = *pc++;
     StkId base, ra;
+count++;
     if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
         (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
       traceexec(L);
@@ -658,20 +665,24 @@ StkId luaV_execute (lua_State *L) {
         break;
       }
       case OP_RETURN: {
-        CallInfo *ci = L->ci - 1;
+        CallInfo *ci = L->ci - 1;  /* previous function frame */
         int b = GETARG_B(i);
+io = count;
         if (b != 0) L->top = ra+b-1;
         lua_assert(L->ci->state & CI_HASFRAME);
         if (L->openupval) luaF_close(L, base);
         L->ci->state = CI_SAVEDPC;  /* deactivate current function */
         L->ci->u.l.savedpc = pc;
         /* previous function was running `here'? */
-        if (!(ci->state & CI_CALLING))
+        if (!(ci->state & CI_CALLING)) {
+          lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc);
           return ra;  /* no: return */
-        else {  /* yes: continue its execution (go through) */
+        }
+        else {  /* yes: continue its execution */
           int nresults;
-          lua_assert(ttisfunction(ci->base - 1));
-          lua_assert(ci->state & CI_SAVEDPC);
+          lua_assert(ci->u.l.pc == &pc &&
+                     ttisfunction(ci->base - 1) &&
+                     (ci->state & CI_SAVEDPC));
           lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL);
           nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1;
           luaD_poscall(L, nresults, ra);