浏览代码

Some bugs with stack reallocation by 'luaF_close'

(Long time without testing with '-DHARDSTACKTESTS'...)
With the introduction of to-be-closed variables, calls to 'luaF_close'
can move the stack, but some call sites where keeping pointers to the
stack without correcting them.
Roberto Ierusalimschy 6 年之前
父节点
当前提交
7e63d3da02
共有 4 个文件被更改,包括 17 次插入17 次删除
  1. 6 3
      ldo.c
  2. 1 1
      ljumptab.h
  3. 1 1
      ltests.c
  4. 9 12
      lvm.c

+ 6 - 3
ldo.c

@@ -383,8 +383,10 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
       wanted = nres;  /* we want all results */
       break;
     default:  /* multiple results (or to-be-closed variables) */
-      if (hastocloseCfunc(wanted)) {
-        luaF_close(L, res, LUA_OK);
+      if (hastocloseCfunc(wanted)) {  /* to-be-closed variables? */
+        ptrdiff_t savedres = savestack(L, res);
+        luaF_close(L, res, LUA_OK);  /* may change the stack */
+        res = restorestack(L, savedres);
         wanted = codeNresults(wanted);  /* correct value */
         if (wanted == LUA_MULTRET)
           wanted = nres;
@@ -590,7 +592,8 @@ static int recover (lua_State *L, int status) {
   if (ci == NULL) return 0;  /* no recovery point */
   /* "finish" luaD_pcall */
   oldtop = restorestack(L, ci->u2.funcidx);
-  luaF_close(L, oldtop, status);
+  luaF_close(L, oldtop, status);  /* may change the stack */
+  oldtop = restorestack(L, ci->u2.funcidx);
   luaD_seterrorobj(L, status, oldtop);
   L->ci = ci;
   L->allowhook = getoah(ci->callstatus);  /* restore original 'allowhook' */

+ 1 - 1
ljumptab.h

@@ -16,7 +16,7 @@
 #define vmbreak		vmfetch(); vmdispatch(GET_OPCODE(i));
 
 
-static void *disptab[] = {
+static void *disptab[NUM_OPCODES] = {
 
 #if 0
 ** you can update the following list with this command:

+ 1 - 1
ltests.c

@@ -142,7 +142,7 @@ void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
     freeblock(mc, block);
     return NULL;
   }
-  if (mc->countlimit != ~0UL && size > 0) {  /* count limit in use? */
+  if (mc->countlimit != ~0UL && size != oldsize) {  /* count limit in use? */
     if (mc->countlimit == 0)
       return NULL;  /* fake a memory allocation error */
     mc->countlimit--;

+ 9 - 12
lvm.c

@@ -946,6 +946,9 @@ void luaV_finishOp (lua_State *L) {
 #define updatebase(ci)	(base = ci->func + 1)
 
 
+#define updatestack(ci) { if (trap) { updatebase(ci); ra = RA(i); } }
+
+
 /*
 ** Execute a jump instruction. The 'updatetrap' allows signals to stop
 ** tight loops. (Without it, the local copy of 'trap' could never change.)
@@ -1557,24 +1560,21 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           L->top = ra + b;
         else  /* previous instruction set top */
           b = cast_int(L->top - ra);
-        savepc(ci);
         if (TESTARG_k(i)) {
           int nparams1 = GETARG_C(i);
           if (nparams1)  /* vararg function? */
             delta = ci->u.l.nextraargs + nparams1;
-          luaF_close(L, base, LUA_OK);  /* close upvalues from current call */
+          /* close upvalues from current call */
+          ProtectNT(luaF_close(L, base, LUA_OK));
+          updatestack(ci);
         }
         if (!ttisfunction(s2v(ra))) {  /* not a function? */
           luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */
           b++;  /* there is now one extra argument */
         }
         if (!ttisLclosure(s2v(ra))) {  /* C function? */
-          luaD_call(L, ra, LUA_MULTRET);  /* call it */
-          updatetrap(ci);
-          if (trap) {  /* stack may have been relocated */
-            updatebase(ci);
-            ra = RA(i);
-          }
+          ProtectNT(luaD_call(L, ra, LUA_MULTRET));  /* call it */
+          updatestack(ci);  /* stack may have been relocated */
           ci->func -= delta;
           luaD_poscall(L, ci, cast_int(L->top - ra));
           return;
@@ -1739,10 +1739,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         memcpy(ra + 4, ra, 3 * sizeof(*ra));
         L->top = ra + 4 + 3;
         Protect(luaD_call(L, ra + 4, GETARG_C(i)));  /* do the call */
-        if (trap) {  /* stack may have changed? */
-          updatebase(ci);  /* keep 'base' correct */
-          ra = RA(i);  /* keep 'ra' correct for next instruction */
-        }
+        updatestack(ci);  /* stack may have changed */
         i = *(pc++);  /* go to next instruction */
         ra += 2;  /* adjust for next instruction */
         lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));